Istruzioni condizionali

Flusso di esecuzione=successione di esecuzione delle istruzioni.

Finora:

  1. sequenza di istruzioni
  2. metodi (salto e ritorno)

Ora vediamo i condizionali: fare qualcosa in base a una condizione.


Un programma con un condizionale

Questo programma stampa a oppure un messaggio.

class PrimoCond {
  public static void main(String args[]) {
    int a;

    a=-3;

    if(a < 0) {
      System.out.println("Il numero e' negativo");
    } 
    else {
      System.out.println(a);
    }
  }
}

Istruzione condizionale: parti

A parole: se una condizione è vera fai una cosa, altrimenti fanne un'altra.

Parti di questa frase:

  1. la condizione
  2. la cosa da fare se la condizione è vera
  3. la cosa da fare se la è falsa.

La seconda e la terza parte sono sequenze di istruzioni.


Forma generale

if (condizione) {
  istruzioni
}
else {
  istruzioni
}

Esempi di condizioni:

a < b
a+b/2-4 >= 9
a == 3+2

Condizioni e valori booleani

Una condizione è una espressione che può essere vera o falsa.

Condizioni elementari:

espressione1 confronto espressione2

espressione1 ed espressione2 sono espressioni

Confronti possibili:

>
>=
==
!=
<
<=

Note: >= si scrive con i due caratteri > ed = senza mettere spazi fra i due

== significa uguale, != significa diverso.


Condizioni vere e false

Una condizione può essere vera o falsa, e può dipendere dai valori delle variabili.

1 > 0
condizione sempre vera
0 > 1
condizione sempre falsa
a > 0
dipende dal valore di a

Attenzione! la condizione 0>1 è falsa, non è un errore!


Assegnazione != uguaglianza

  a=0;

  if(a==0) ...

Differenza:

a=0
metti 0 nella variabile a
a==0
il contenuto della variabile è zero?

La prima è una istruzione (un comando), la seconda è una domanda.


Esercizio: fare la divisione

Leggere due interi, e fare la divisione se possibile, altrimenti stampare messaggio di errore.

Forma della istruzione condizionale:

  if(condizione) {
    istruzioni;
  }
  else {
    istruzioni;
  }

Divisione: soluzione

Primo: si leggono due interi.

import javax.swing.*;

class Dividi {
  public static void main(String args[]) {
    int x, y;
    String s;

    s=JOptionPane.showInputDialog("Dividendo");
    x=Integer.parseInt(s);

    s=JOptionPane.showInputDialog("Divisore");
    y=Integer.parseInt(s);

    // qui va fatta la divisione
  }
}

Seconda parte: il condizionale

Se y vale 0 si deve solo stampare il messaggio di errore.


    if(y==0) {
      System.out.println("Il divisore deve essere diverso da zero");
    }
    else {
      System.out.println(x/y);
    }


Programma completo

import javax.swing.*;

class Dividi {
  public static void main(String args[]) {
    int x, y;
    String s;

    s=JOptionPane.showInputDialog("Dividendo");
    x=Integer.parseInt(s);

    s=JOptionPane.showInputDialog("Divisore");
    y=Integer.parseInt(s);

    if(y==0) {
      System.out.println("Il divisore deve essere diverso da zero");
    }
    else {
      System.out.println(x/y);
    }

    System.exit(0);
  }
}

Condizioni negate

Si poteva anche fare:

  if(y!=0) {
    System.out.println(x/y);
  }
  else {
    System.out.println("Il divisore deve essere diverso da zero");
  }

Condizioni opposte:

Condizione Opposto
== !=
>= <
<= >

> non è il contrario di <


Diagramma di flusso

Indica il percorso delle istruzioni da eseguire.

Il blocco if (...) {...} else {...} si comporta come una unica istruzione.

Quindi, una volta finito, is passa comunque alla istruzione successiva.


Condizioni senza ramo else

La parte else {...} si può omettere.

Equivale a scrivere else { }, ossia parte else senza istruzioni.

Esempio:

  if(x<0) {
    System.out.println("Numero negativo");
  }

  System.out.println("Programma terminato");

Cosa viene stampato?


Soluzione

Se a è negativo: vengono stampate tutte e due le stringhe.

Altrimenti, viene stampata la seconda.


Diagramma di flusso

Se la parte else non c'è, è come se fosse vuota.

Di solito, viene più comodo disegnato cosí:

Se x<0 si esegue la prima println

Altrimenti no

In ogni caso si passa ad eseguire l'istruzione dopo tutto l'if


Esercizio

Scrivere un programma che prende due numeri, e stampa solo quelli positivi, e poi stampa la somma dei due comunque.


Soluzione

Per ogni intero letto, lo devo stampare solo se è positivo; poi stampo la somma (anche se sono negativi).

Se è negativo non lo stampo, ma passo comunque al successivo.

Posso usare due if senza else


Soluzione: sequenza

Devo fare tre cose:

  stampa il primo se positivo
  stampa il secondo se positivo
  stampa la somma

Vanno fatte in sequenza, e vanno fatte tutte e tre!

La terza di traduce direttamente

La prima is realizza con un if

    if(x>=0) {
      System.out.println(x);
    }

Lo stesso per la seconda


Programma completo

Faccio la sequenza dei tre passi

import javax.swing.*;

class DuePos {
  public static void main(String args[]) {
    String s;
    int x, y;

    s=JOptionPane.showInputDialog("Dammi un numero");
    x=Integer.parseInt(s);

    s=JOptionPane.showInputDialog("Dammi un numero");
    y=Integer.parseInt(s);

    if(x>=0) {
      System.out.println(x);
    }

    if(y>=0) {
      System.out.println(x);
    }

    System.out.println(x+y);

    System.exit(0);
  }
}

Raffinamenti successivi

Siamo partiti dalla sequenza:

  stampa il primo se positivo
  stampa il secondo se positivo
  stampa la somma

Poi abbiamo sviluppato ognuno dei tre punti.

Per realizzare il punto 1, non ci serve sapere che ci sono anche gli altri due

Potevamo fare finta che gli altri due punti non ci fossero.

Vantaggio: ci possiamo concentrare su un sottoproblema per volta.


Condizionali nidificati

Costrutto, in generale:

if(condizione)
  istruzione1;
else
  istruzione2;

Altra regola generale:

dove si può mettere una istruzione, si può mettere una sequenza fra graffe

Ultima regola:

dove si può mettere una istruzione, si può mettere un condizionale

Quindi, all'interno di un condizionale si può mettere un altro condizionale

In questo caso, è meglio usare le graffe (vedremo poi il perchè)


Condizionali nidificati: esercizio

Creare una classe QuadPoint che ha le stesse componenti di Point, ma in più un metodo che ritorna 1 se il punto sta nel primo quadrante, altrimenti 0.


Soluzione: punto 1

Il problema non è facile?

Una parte per volta!

Se x è positivo, cosa si ritorna?

Si ritorna 1 se anche y è positivo, altrimenti 0

Se x è negativo, si ritorna 0


Soluzione, con due if/else

class PointQuad {
  int x;
  int y;

  int quadrante() {
    if(this.x>=0) {
      if(this.y>=0) {
        return 1;
      }
      else {
        return 0;
      }
    }
    else {
      return 0;
    }
  }
}

Interpretazione: ad alto livello, si tratta di un if

    if(this.x>=0) {
      ...
    else {
      return 0;
    }

In cui la sequenza da eseguire in caso la condizione sia vera è un altro if:

      if(this.y>=0) {
        return 1;
      }
      else {
        return 0;
      }

In questo programma non abbiamo usato istruzioni nuove.

Abbiamo solo composto le istruzioni già viste.


Soluzione, con due if

Soluzione alternativa più semplice:

class PointQuad {
  int x;
  int y;

  int quadrante() {
    if(this.x>=0) 
      if(this.y>=0) 
        return 1;

    return 0;
  }
}

Funziona perchè:

  1. return, oltre a dire il valore calcolato, termina l'esecuzione del metodo
  2. dopo un if, si esegue l'istruzione dopo

Operatori booleani

In questo esempio: se this.x è positivo e this.y è positivo, allora fai una certa cosa.

La cosa da fare dipende da due condizioni this.x>=0 e this.y>=0

Se sia this.x>=0 che this.y>=0 sono vere si deve ritornare 1, altrimenti 0

Quando voglio fare una cosa se due condizioni sono tutte e due vere, le combino con && (and)

class PointQuad {
  int x;
  int y;

  int quadrante() {
    if( (this.x>=0) && (this.y>=0) )
        return 1;
    else
      return 0;
  }
}

Secondo operatore booleano: or

Se ho due condizioni c1 e c2, allora c1 || c2 è vera se lo è almeno una delle due.


Esercizio

Leggere due interi, stampare la somma se almeno uno dei due è positivo.


Soluzione, con ||

La stampa va fatta se la condizione x>=0, ma anche se y>=0 è vera.

La condizione composta (x>=0) || (y>=0) è vera se lo è almeno una delle due condizioni che la compongono.

import javax.swing.*;

class UnPos {
  public static void main(String args[]) {
    String s;
    int x, y;

    s=JOptionPane.showInputDialog("Dammi un numero");
    x=Integer.parseInt(s);

    s=JOptionPane.showInputDialog("Dammi un numero");
    y=Integer.parseInt(s);

    if( (x>=0) || (y>=0) ) {
      System.out.println(x+y);
    }

    System.exit(0);
  }
}

Soluzione senza or

Si poteva fare anche senza:

    if(x>=0) {
      System.out.println(x+y);
    }
    if(y>=0) {
      System.out.println(x+y);
    }

La soluzione che usa || è più semplice e più facile da leggere.


Condizionali annidati

  if(cond)
    istr1;
  else
    istr2;

La seconda istruzione può essere un altro if

Cascata di istruzioni condizionali:

  if(cond)
    istr;
  else if(cond)
    istr;
  else if(cond)
    istr;
  else
    istr;

Esercizio

Dato un numero intero maggiore o uguale a zero, stampare il suo valore in lettere, se è minore di cinque.

Se il numero è superiore a cinque, stampare un messaggio di errore.


Soluzione

Confronto il valore con 0, poi 1, ecc.

class Lettere {
  public static void main(String args[]) {
    int n=3;

    if(n==0)
      System.out.println("zero");
    else if(n==1)
      System.out.println("uno");
    else if(n==2)
      System.out.println("due");
    else if(n==3)
      System.out.println("tre");
    else if(n==4)
      System.out.println("quattro");
    else if(n==5)
      System.out.println("cinque");
    else
      System.out.println("non lo stampo, questo numero");
  }
}

Ambiguità sintattica dell'if

Cosa significa questo programma?

if(cond1)
if(cond2)
istr1;
else
istr2;

Mettere le graffe e l'indentazione.

Due soluzioni possibili.


Le due soluzioni

Prima soluzione:

 
if(cond1) {
  if(cond2)
    istr1;
}
else
  istr2;

Seconda soluzione:

if(cond1) {
  if(cond2)
    istr1;
  else
    istr2;
}

Regola di Java: l'else si considera il ramo ``condizione falsa'' dell'ultimo if.

Quindi, istr2 viene eseguito solo se cond1 è vera ma cond2 è falsa.


Esercizio

Cosa stampa questo programma?

  if(x>=0)
    if(x<=10)
      System.out.println("Il numero sta fra 0 e 10");
  else
    System.out.println("Il numero e' negativo");

Soluzione

L'indentazione può trarre in inganno.

L'else fa parte dell'ultimo if:

  if(x>=0) {
    if(x<=10)
      System.out.println("Il numero sta fra 0 e 10");
    else
      System.out.println("Il numero e' negativo");
  }

Il programma è quindi sbagliato.


Errore tipico

Questo errore viene prima o poi commesso.

Per trovare un errore, occorre ``mettersi nei panni del computer'', ossia eseguire le istruzioni nello stesso modo in cui lo fa lui.

Dato che lui attacca l'else all'ultimo if, il programma stampa che il numero è negativo quando invece è positivo ma maggiore di dieci.

Per una persona è chiaro cosa andava fatto sulla base delle stringhe stampate.

Per il calcolatore le stringhe sono solo sequenze di caratteri. L'interpretazione delle istruzioni è meccanica.