1 Villkor och styrsatser I de program vi sett tidigare har programkörning inneburit att sats efter sats utförts i den ordning de skrivits i källkoden. Vi har inte kunna ändra programmets uppförande beroende på inmatningar eller beräkningsresultat. Vi kallar en sådan samling satser för en sekvens, eftersom de utförs en efter en. Sekvens: Start: Sats1 -> sats 2 -> sats 3 -> sats 4 Slut. Vi ska nu titta på en ny struktur som kallas för selektion. Selektion innebär att programmet kan under programkörning fatta beslut om vilken av en, två eller flera alternativa sekvenser som ska utföras. 1.1 Villkorssatsen if En villkorssats är den konstruktion som finns i java för att göra en selektion av två alternativa sekvenser. Eller om man så vill, välja en av två möjliga vägar beroende på ett villkor. Formen för if- satsen är alternativt if ( logiskt_uttryck ) sats / satsblock else sats / satsblock if ( logiskt_uttryck ) sats / satsblock Det logiska uttrycket anger ett villkor som är antingen sant eller falskt. Den första sats/satsblocksdelen är det programavsnitt som ska utföras om villkoret är sant. Den andra sats/satsblocksdelen är det som ska utföras om villkoret är falskt. else och det efterföljande sats/satsblock är valfritt. Några enkla exempel: Scanner tgb = new Scanner(System.in); int antalhusdjur; System.out.println("Ange hur många husdjur du har hemma"); antalhusdjur = tgb.nextint(); System.out.println("Jaså du har "+ antalhusdjur+ " husdjur"); if ( antalhusdjur > 5 ) System.out.println("Oj det var många); Programavsnittet måste fogas in i ex public static void main(... ) metod för att fungera. Detta program har nu två möjliga vägar att gå: 1. Villkoret är sant. Användaren har matat in en siffra större än 5. Ange hur många husdjur du har hemma 12 Jaså du har 12 husdjur Oj det var många 2. Villkoret är falskt. Användaren har matat in en siffra som är 5 eller lägre.
Ange hur många husdjur du har hemma 2 Jaså du har 2 husdjur Villkorssatsen i exemplet utnyttjar att else delen av if satsen är valfri. Dessutom läggs det en sats och inte ett satsblock efter if satsen. if satsen väljer bara den sats som ligger direkt efter villkoret. Notera indragningen av satsen System.out.println( "Oj det var många" ); Indragningen är densamma som ses efter klammern { efter main(... ). Syftet med indragningen är att då man läser programmet ska man enkelt kunna se vilken eller vilka satser som hör till villkoret, eller för mainmetoden ska man enkelt kunna se vilka satser som ligger i metoden. Indraget bör vara 2-4 mellanslag. Var konsekvent. 1.1.1 Satsblock För att kunna utföra flera satser styrda av ett villkor konstruerar man ett satsblock. Ett satsblock är helt enkelt en sekvens av satser omgärdade av { och klamrar. Funktionen main() har också ett satsblock, klamrarna { och som anger början respektive slut på programmet. Ett liknande program med satsblock och else satser int antal_husdjur; Scanner tgb = new Scanner(System.in); System.out.println("Ange hur många husdjur du har hemma"); antalhusdjur = tgb.nextint(); if ( antalhusdjur > 5 ){ System.out.print("Oj det var många, hela "); System.out.println( antalhusdjur + " stycken"); else{ System.out.print("Jaså du har bara"); System.out.println( antalhusdjur+ " stycken"); Observera hur indraget, indentering, går över hela satsblocken. Programmet kommer nu att välja endast en av vägarna efter if satsen. Om villkoret är uppfyllt utförs satsblocket direkt efter villkoret, annars utförs satsblocket efter else. 1.1.2 Övning: Sätt in ovanstående exempel i ett komplett program och provkör. Blev resultatet det du förväntade dig? Kontrollera indenteringen i det program du skapat. Ett vanligt fel är att man råkar lägga en ensam sats mellan if satsen och satsblocket. Kompilatorn har svårt att ge en rimlig felbeskrivning för detta fel. Ett annat vanligt fel är att man påbörjar satsblocket innan villkorssatsen eller else. Satsblocket blir då som regel betydelselöst.
{ if ( antalhusdjur > 5 ) // FEL! Satsblocket börjar inte direkt efter villkoret System.out.print("Oj det var många hela "); System.out.println( antalhusdjur+ " stycken"); else System.out.println("Jaså du har bara"); { // FEL! Satsblocket börjar inte direkt efter else satsen. System.out.println( antalhusdjur+ " stycken"); Det händer också att man ibland råkar sätta ett semikolon direkt efter if satsens villkor. if ( längd < 30.7 ); // FEL! System.out.println("kort längd"); Detta får till följd att en tom sats direkt efter villkoret styrs av if satsen. Eftersom satsen är tom påverkar den inte programmet på något sätt. System.out satsen däremot som var tänkt att påverkas av villkoret utförs oavsett resultatet på villkoret eftersom if satsen tar slut i och med semikolonet. Ett annat misstag som är vanligt är att man missar avgränsningen till else boolean turnedon = false; if ( turnedon ){ System.out.println("Påslagen!"); else System.out.println("Avslagen!"); else är här satt i fel kontext. else är inte ett giltigt nyckelord i satsblocket. Det korrekta är boolean turnedon = false; if ( turnedon ){ System.out.println("Påslagen!"); else{ System.out.println("Avslagen!"); 1.2 Logiska villkor I och med villkorssatsen stöter vi på en ny typ av uttryck, de logiska operatorerna. De logiska uttrycken följer samma mönster som de tidigare operationerna vi sett med den skillnaden att resultatet av en logisk operation alltid är ett booleskt(logiskt) värde, sant eller falskt, datatyp boolean. Operatorerna som ger logiska resultat kallas, logiskt nog, logiska operatorer.
Logiska binära operatorer == Lika med!= Icke lika med < Mindre än <= Mindre än lika med > Större än >= Större än lika med && Logiskt AND Logiskt OR Varje logisk operation ger ett resultat av typen boolean. Man kan använda sig av variabler deklarerade med typen boolean för att lagra logiska värden. Det är emellertid inte speciellt vanligt med booleandeklarerade variabler, boolska uttryck konstrueras oftast i Villkoret i exemplet ovan hade kunnat skrivas utförligare som: boolean mangahusdjur; mangahusdjur = antalhusdjur > 5; if ( mangahusdjur ) // satsblocken som tidigare med samma betydelse. Variabeln mangahusdjur kan alltså anta värdena true eller false. De flesta logiska operationer är tämligen rättframma. Här följer några exempel på hur uttrycken kan se ut: Antag att förekommande variabler är deklarerade med en rimlig datatyp ( vikt < 60.0 ) ( antalhundar== 2 ) ( antalvalar!= 2 ) // motsatsen till ovan ( antal*2 >= 52 ) // räkneoperationen utvärderas först Man kan dessutom kombinera uttryck med de logiska operatorerna && ( OCH ) och (ELLER). Dessa operatorer har formen ( boolean ) && ( boolean ): boolean ( boolean ) ( boolean ): boolean Man använder alltså dessa operatorer på logiska värden eller uttryck ( antal == 2 && vikt < 20.0 )// båda jämförelserna måste vara sanna för // att hela uttrycket ska vara sant ( antal == 2 vikt < 20.0 ) // om någon av jämförelserna är sanna // är uttrycket sant Det finns även en unär logisk operator!, icke. Operatorn fungerar så att den vänder ett sant värde falskt, och tvärtom. Exempel (!( 3 > 4 ) ) // är sant (!( 7 == 12 ) ) // är sant (!(4==4) ) // är falskt Det bör sägas ett varningens ord om likhetsjämförelser av flyttal. Om man har två flyttal är det ofta svårt att kontrollera om de är lika, eftersom jämförelsen kräver att de är lika med stor noggrannhet. I varningars tidevarv får man inte glömma bort att varna för en viss typ av sammansatta jämförelser. Betrakta följande programavsnitt
int hurgammal; Scanner tgb = new Scanner(System.in); System.out.println("Ange din ålder "); hurgammal = tgb.nextint(); // kolla om tonåring, äldre än 12 och yngre än 20 år if ( 12 < hurgammal < 20 ) // FEL! { System.out.println("Du är tonåring"); Villkoret kan till en början se riktigt ut, kompilatorn upptäcker nödvändigtvis inget fel. Faktum är att skrivsättet är väldigt vanligt inom algebra. Om man däremot ser i detalj vad villkoret utvärderar ser man ett problem. Den första operationen som utförs är jämförelsen ( från vänster till höger ) 12 < hurgammal resultatet av denna operation är av typen bool och används som vänster operand i nästa < operation. Resultatet av uttrycket är antingen true eller false, nästa jämförelse blir därför true < 20 om hurgammal var större än 12 annars false < 20 Resultatet blir kompileringsfel, boolean kan inte befodras till int. För att skriva jämförelsen på ett riktigt sätt måste man dela upp den i två jämförelser, dels 12 < hurgammal och dels i hurgammal < 20 kombinerade med && (and). // kolla om tonåring, äldre än 12 och yngre än 20 år if ( 12 < hurgammal && hurgammal < 20 ) // RÄTT! { System.out.println("Du är tonåring"); 1.2.1 Nästlade if satser Ett sats i satsblocket kan innehålla vilken annan typ av sats som helst, även andra if satser. Ett villkor sammansatt med && kan även skrivas om som ett nästlat villkor // kolla om tonåring, äldre än 12 och yngre än 20 år alternativ lösning if ( hurgammal > 12) { // personen är äldre än 12 if ( hurgammal < 20 ) System.out.println("Du är tonåring"); Var uppmärksam på skillnaden mellan denna konstruktion och
// kolla om tonåring, äldre än 12 och yngre än 20 år felaktig lösning if ( hurgammal > 12) // personen är äldre än 12 System.out.println("Du är äldre än 12"<<endl; if ( hurgammal < 20 ) // personen är äldre än 20 System.out.println("Du yngre än 20"); Se också hur indenteringen ändras för nästlade satser. Observera att kommentarerna inte påverkar if satserna och de satser de styr. Testa gärna de olika varianterna vid en dator. Exempel, enkel sortering av två tal import java.util.*; class NumberOrder { public static void main(string [] arg){ double tal1, tal2; Scanner tgb = new Scanner( System.in ); // ledtext System.out.println("Vilket av två tal är störst?"); System.out.println("Ange det första talet:"); tal1 = tgb.nextdouble(); System.out.println("Ange det andra talet:"); tal2 = tgb.nextdouble(); if ( tal1 > tal2 ){ System.out.print(""Det första talet, " + tal1); System.out.println(" är störst"); else{ System.out.println("Det andra talet, "+tal2+" är störst"); 1.2.2 Övning Komplettera programmet så att det även skriver ut det mindre av talen. Vad händer om talen är lika?