Esempi di istruzioni condizionali

In molti algoritmi, l'esecuzione di uno o più passi può dipendere da certe condizioni (valori in input, stato della memoria,...). Per controllare l'esecuzione di questi passi si può usare l'istruzione condizionale if-else.

Abbiamo già visto alcuni esempi:

// if semplice
if (x == 0) System.out.println("x vale zero"); 
     //  la stringa viene stampata solo se x e' uguale 
     //  a zero cioe' se la condizione e' vera 


// if-else if (x > y) System.out.println("x e' maggiore di y");   else   System.out.println("y e' maggiore di o uguale a x");      //  il ramo 'else' viene eseguito solo       //  se la condizione e' falsa 
// if-else in cascata if (x > y) System.out.println("x e' maggiore di y");   else if (x < y) System.out.println("y e' maggiore di x");   else  System.out.println("x e y sono uguali"); 




Istruzioni if e if-else: Sintassi

if ( <condizione> )
    <istruzione-1>

oppure

if ( <condizione> )
    <istruzione-1>
else <istruzione-2>

dove:

  • <condizione> è un'espressione booleana
  • <istruzione-1> e <istruzione-2> possono essere:
  • istruzioni semplici
  • istruzione composte
  • blocchi di istruzioni



Istruzioni if e if-else: Significato

if ( <condizione> )
    <istruzione-1>
else <istruzione-2>
  1. L'istruzione if valuta la <condizione>
    • Se la valutazione ritorna il valore true esegue <istruzione-1>.
    • Se la valutazione ritorna il valore false esegue <istruzione-2> (se presente).
  2. In ogni caso, l'esecuzione passa poi all'istruzione successiva al comando if.
Le istruzioni if possono essere annidate: in questo caso, per evitare ambiguità, ogni else si riferisce al primo if che lo precede.

In caso di annidamento, una corretta indentazione del codice e l'uso di parentesi graffe possono facilitare e disambiguare la lettura del programma.




Istruzioni if e if-else annidati

Supponiamo di voler esprimere un giudizio sul voto di un esame universitario in base alla seguente classificazione:
if, con if-else annidato
public class Giudizio1 {

    public static void main(String[] args) {

        System.out.println("Immetti un voto:");
        int  voto = Input.readInt();

        if ( voto>=18 && voto<=30 )
            if ( voto>=24 )
                System.out.println("Il risultato e' buono");
            else 
                System.out.println("Il risultato e' sufficiente");
           
    }
}

if-else, con if annidato
public class Giudizio2 {

    public static void main(String[] args) {

        System.out.println("Immetti un voto:");
        int  voto = Input.readInt();

        if ( voto>=24 ) 
            {
                if ( voto<=30 )  
                    System.out.println("Il risultato e' buono");
            }
        else
            if ( voto>=18 ) 
                System.out.println("Il risultato e' sufficiente");
           
    }
}

if con if annidato, seguito da un if ... ma cosa succede quando voto==25?
public class GiudizioErr {

    public static void main(String[] args) {

        System.out.println("Immetti un voto:");
        int  voto = Input.readInt();

        if ( voto>=24 ) 
            {
                if ( voto<=30 )  
                    System.out.println("Il risultato e' buono");
            }
        if ( voto>=18 ) 
            System.out.println("Il risultato e' sufficiente");
           
    }
}



Altri esempi (1)

if-else con blocchi di istruzioni
    ...
    boolean min100;
    if  (i < 100) {
       System.out.println ("minore di 100");
       min100 = true;
    } else {
       System.out.println ("maggiore o uguale a 100");
       min100 = false;
    }
    ...


if-else annidati... con pessima spaziatura
    ...
    if (i < 100) if (i > 0)
       System.out.println ("minore di 100 e maggiore di zero");
    else
    // siamo nel caso i>=100 oppure i<=0?
       System.out.println (???);
    ...


if-else annidati con spaziatura che favorisce leggibilità
    ...
    if (i < 100)
       if (i > 0)
          System.out.println ("minore di 100 e maggiore di zero");
       else
          System.out.println ("minore o uguale a zero");
    else
       if (i == 100)
          System.out.println ("uguale a 100");
       else
          System.out.println ("maggiore di 100");
    ...




Altri esempi (2)

ScambioVariabili.java
public class ScambioVariabili {

    public static void main (String [] args) {

        System.out.print ("Dammi x: ");
        int x = Input.readInt();
        System.out.print ("Dammi y: ");
        int y = Input.readInt();

        System.out.println ("x = " + x + ", y = " + y);

        // scambia il valore delle due variabili 
        // solo se x > y 
        if ( x > y ) {
            // per scambiare i valori e' necessaria una
            // variabile di appoggio!
            int temp = x;  
            x = y;         
            y = temp;     
        }

        System.out.println ("x = " + x + ", y = " + y);
    }
}






Comandi condizionali a più vie

Supponiamo di voler scrivere un comando che assegni alla variabile String giorno il nome del giorno lavorativo corrispondente al day-esimo giorno della settimana, oppure la stringa "Week-end". Usando i comandi if-else otteniamo:
 

Catena di if-else "naive"
    if (day == 1)
       giorno = "Monday";
    else if (day == 2)
       giorno = "Tuesday";
    else if (day == 3)
       giorno = "Wednesday";
    else if (day == 4)
       giorno = "Thursday";
    else if (day == 5)
       giorno = "Friday";
    else if (day == 6 || day == 7)
       giorno = "Week-end";
    else
       giorno = null;
    ...

Una serie di if-else nei quali vogliamo confrontare un singolo valore intero rispetto a diversi valori costanti alternativi può essere realizzata mediante il comando condizionale "a più vie" switch.
 

 




Istruzione switch: Sintassi

switch ( <selettore> ) {
   case <valore1> : <istruzioni1>
   case <valore2> : <istruzioni2>
   ...
   default: <istruzioniN>
}
  • <selettore> è un'espressione che fornisce un risultato di tipo char, byte, short, int, o di un tipo enumerativo.
  • <valoreX>  è un'espressione costante dello stesso tipo del <selettore>. Ogni <valoreX>  deve essere unico.
  • <istruzioniX> può essere:
  • una sequenza di istruzioni e dichiarazioni di variabili
  • un blocco di istruzioni
  • default può essere presente una sola volta.
Quello che segue la parte (<selettore>)  deve essere un blocco, che può essere vuoto o iniziare con case o default.

Nel caso in cui esistano un <valoreX> e <valoreY> per i quali <istruzioniX> è uguale a <istruzioniY> allora il comando switch può essere scritto nella sua forma più generale e compatta:

switch ( <selettore> ) {
   case <valore1> : <istruzioni1>
   case <valore2> : <istruzioni2>
   ...
   case <valoreX> :
   case <valoreY> : <istruzioniY>
   ...
   default: <istruzioniN>
}



Istruzione switch: Significato

switch ( <selettore> ) {
   case <valore1> : <istruzioni1>
   case <valore2> : <istruzioni2>
   ...
   case <valoreX> :
   case <valoreY> : <istruzioniY>
   ...
   default: <istruzioniN>
}
  1. L'istruzione switch valuta il <selettore> ed esegue il blocco sequenzialmente.
  2. Scorrendo il blocco possono verificarsi tre casi:
    • Se incontra un'etichetta case seguita da un <valoreY> uguale al risultato del <selettore>, esegue le <istruzioniY> corrispondenti e tutte le successive <istruzioniY+1>...<istruzioniN>.
    • Se invece nessuno dei <valoreY> è uguale alla valutazione del <selettore> ma è presente l'etichetta default, allora esegue le <istruzioniN> corrispondenti.
    • Se invece nessuno dei <valoreY> è uguale alla valutazione del <selettore> e non è presente neppure l'etichetta default, allora passa al punto 3.
  3. L'esecuzione passa infine all'istruzione immediatamente successiva al blocco dello switch.
Anche le istruzioni switch possono essere annidate.



Istruzione break nello switch

Per evitare che vengano valutate tutte le  <istruzioniY+1>...<istruzioniN>  successive a quelle di un case soddisfatto si utilizza l'istruzione break.

Il break permette di trasferire l'esecuzione all'istruzione immediatamente successiva al blocco dello switch. Tipicamente break viene posto come ultima istruzione di ogni case (ovvero dopo ogni <istruzioniX>).

L'istruzione switch si utilizza quindi (solitamente) nella forma:
 
 

switch ( <selettore> ) {
   case <valore1> : <istruzioni1> break;
   case <valore2> : <istruzioni2> break;
   ...
   case <valoreX> :
   case <valoreY> : <istruzioniY> break;
   ...
   default: <istruzioniN> break;
}

Esempio:

Giorni della settimana con switch e break
switch ( day ) {
   case 1: giorno = "Monday"break;
   case 2: giorno = "Tuesday"break;
   case 3: giorno = "Wednesday"break;
   case 4: giorno = "Thursday"break;
   case 5: giorno = "Friday"break;
   case 6: // Saturday, ...
   case 7: giorno = "Week-end"break// ... Sunday
   default: giorno = null// Tutti gli altri casi.
}



If-else versus switch

Attenzione: l'enunciato switch si può usare solo in circostanze limitate. I valori con i quali si può confrontare il selettore devono essere costanti di tipo intero, char o enumerativo: non si può usare lo switch ad esempio con un selettore di tipo double o String.

Anche quando è lecito, non sono molti i casi in cui è opportuno che l'istruzione switch sostituisca l'istruzione if-else.

Torniamo al problema di voler esprimere un giudizio sul voto di un esame universitario in base alla classificazione:

  • se il voto è compreso tra 18 e 23 allora il giudizio sarà sufficiente;
  • se il voto è compreso tra 24 e 30 allora il giudizio sarà buono

Invece del programma
if con if-else annidato
public class Giudizio1 {

    public static void main(String[] args) {

        System.out.println("Immetti un voto:");
        int  voto = Input.readInt();

        if ( voto>=18 && voto<=30 )
            if ( voto>=24 )
                System.out.println("Il risultato e' buono");
            else 
                System.out.println("Il risultato e' sufficiente");
           
    }
}

Potremmo avere l'idea di usare uno switch

switch
public class Giudizio3 {

    public static void main(String[] args) {

        System.out.println("Immetti un voto:");
        int  voto = Input.readInt();

        switch  (voto)  
            {
            case 18:case 19: case 20: case 21: case 22: case 23:
                System.out.println("Il risultato e' sufficiente");
                break;
        
            case 24:case 25: case 26: case 27: case 28: case 29: case 30: 
                System.out.println("Il risultato e' buono");
            }
    }
}

In questo caso, il programma che usa lo switch non sarebbe altrettanto leggibile e compatto.




Istruzione switch : altri esempi

Una versione con tipi enumerativi
public class SettimanaEnum {

        enum WeekDay {
                MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        }

        public static void main(String[] args) {
                String giorno;
                WeekDay day = WeekDay.SUNDAY;
                switch (day) {
                case MONDAY:
                        giorno = "Monday";
                        break;
                case TUESDAY:
                        giorno = "Tuesday";
                        break;
                case WEDNESDAY:
                        giorno = "Wednesday";
                        break;
                case THURSDAY:
                        giorno = "Thursday";
                        break;
                case FRIDAY:
                        giorno = "Friday";
                        break;
                case SATURDAY:
                case SUNDAY:
                        giorno = "Week-end";
                        break;
                default:
                        giorno = null;
                }
                System.out.println(day + " = " + giorno);
        }
}

Riconosce se un numero x compreso tra 1 e 10 è primo
switch (x) {
   case 2: // va  al successivo
   case 3: // va  al successivo
   case 5: // va  al successivo
   case 7:
      System.out.print (x);
      System.out.println (" è un numero primo");
      break;
   case 1: // va  al successivo
   case 4: // va  al successivo
   case 6: // va  al successivo
   case 8: // va  al successivo
   case 9: // va  al successivo
   case 10:
      System.out.print (x);
      System.out.println (" non è un numero primo");
      break;
   default:
      System.out.print (x);
      System.out.println (" è minore di 1 o maggiore di 10");
}




Istruzioni condizionali: errori tipici

Di seguito vengono evidenziati alcuni (schemi di) errori molto frequenti per aiutarvi a comprenderne le cause ed evitarli.
  • Uso dell'operatore di assegnamento invece che di confronto:
       if ( x = 0 )
          System.out.println("x vale 0");
    

  • if con comando vuoto
       if ( x == 0 );
          System.out.println("x vale 0");
    

  • if-else senza blocchi
       if ( x <= y ) // manca {
          System.out.print(x);
          System.out.print(" e' minore o uguale a ");
          System.out.println(y);
       // manca }
       else  // manca {
          System.out.print(x);
          System.out.print(" e' maggiore di ");
          System.out.println(y);
       // manca }
    

  • omissione di else
       if ( x == 0 ) x = 1;
       // manca else
       if ( x == 1 ) x = 0;
       System.out.print(x); 
    

  • omissione di break
       switch (x) {
          case 2: case 3: case 5: case 7:
             System.out.print (x);
             System.out.println (" è un numero primo");
             // manca break;
          case 1: case 4: case 6: case 8: case 9: case 10:
             System.out.print (x);
             System.out.println (" non è un numero primo");
             // manca break;
          default:
             System.out.print (x);
             System.out.println (" è minore di 1 o maggiore di 10");
       }
    





Espressioni condizionali

Per completezza, vediamo anche le espressioni condizionali che, nel caso particolare del calcolo di un valore, possono offrire una notazione più compatta rispetto all'if-else.

Sono una eredità  di C e C++.

Sintassi:

<condizione> ? <espressione1> : <espressione2>

Significato: è una espressione, non un comando.

  • se la <condizione> vale true, il risultato è il valore di <espressione1>.

  • se la <condizione> vale false, il risultato è il valore di <espressione2>.

Esempio:

int x = 0;
int y = (x != 0) ? 5/x : 5;