04. Corso completo di Programmazione Java – Controllo del Flusso

Corso Java - Controllo del Flusso

Un giorno le macchine saranno in grado di prendere decisioni autonomamente e supereranno la (limitata) capacità intellettiva dell’uomo. Fino a quel giorno però i programmatori dovranno indicare ai computer cosa fare nel caso di ogni bivio decisionale. Per questo motivo in tutti i linguaggi di programmazione esistono i costrutti di controllo del flusso (Control Flow). In questo post vediamo insieme quali sono quelli offerti dal linguaggio Java e come usarli.

Nota per i programmatori C++

I costrutti di controllo del flusso offerti da Java sono praticamente uguali a quelli del C++: per voi dovrebbe quindi essere molto naturale usarli. Solo con Java 5 è stato introdotto un nuovo costrutto per ciclare, il foreach, molto elegante e potente.

Ma prima di iniziare…

Prima di affrontare i costrutti condizionali abbiamo bisogno di dire due parole sui blocchi. Un blocco o statement composto è un numero qualsiasi di statement Java raggruppati in una coppia di parentesi graffe. I blocchi definiscono anche quello che si chiama lo scope, ovvero la visibilità delle variabili: una variabile dichiarata all’interno di un blocco ha visibilità solo dentro al blocco stesso. I blocchi possono essere annidati:

public static void main(String[] args)
{
   int n;
   . . .
   {
      int k;
      . . .
   } // k è definita fino a qua
}

Non è possibile dichiarare variabili con lo stesso nome in due blocchi annidati: il codice seguente non viene compilato:

public static void main(String[] args)
{
   int n;
   . . .
   {
      int k;
      int n; // errore
      . . .
   }
}
Nota per i programmatori C++

In C++ è possibile ridefinire una variabile in un blocco annidato e la definizione più interna maschera quella più esterna. Poiché questo può essere fonte di potenziali errori di programmazione in Java non è stato consentito.

Costrutti condizionali

Il costrutto condizionale per eccellenza è l’IF:

if (condition) statement

La condizione, che deve essere valutabile a boolean (true o false), è circondata da parentesi: se risulta essere true viene eseguito lo statement, in caso contrario non viene eseguito. Se vogliamo eseguire più di uno statement nel caso in cui la condizione sia true dobbiamo creare un block statement, ovvero un insieme di condizioni raggruppate insieme da parentesi graffe:

if (condition)
{
   statement1
   statement2
   . . .
}

La forma più completa prevede anche una parte opzionale: cosa fare nel caso in cui la condizione sia false, quello che viene spesso chiamato il ramo else:

if (condition) statement1 else statement2

Vediamo un esempio:

if (yourSales >= 2 * target)
{
   performance = "Excellent";
   bonus = 1000;
}
else if (yourSales >= 1.5 * target)
{
   performance = "Fine";
   bonus = 500;
}
else if (yourSales >= target)
{
   performance = "Satisfactory";
   bonus = 100;
}
else
{
   System.out.println("You're fired");
}

Il codice di cui sopra realizza quando illustrato nel diagramma di flusso seguente:


Diagramma di Flusso

Come si vede è possibile utilizzare più alternative if . . . else if . . ., anzi la cosa è abbastanza comune; tuttavia vedremo in uno dei post più avanzati come esagerare con questi costrutti, rendendoli molto complessi, può portare a codice facile da “rompere” e difficile da manutenere.

Costrutti iterativi

Fanno parte dei costrutti di controllo del flusso anche quei costrutti che affermano quante volte o in base a quale condizione ripetere l’esecuzione di un block statement, i cosiddetti Costrutti iterativi.

Il costrutto While

Il loop while esegue uno statement o un block statement fino a che la condizione è true:

while (condition) statement

Vediamo un esempio:

class WhileDemo {
     public static void main(String[] args){
          int count = 1;
          while (count < 11) {
               System.out.println("Count is: " + count);
               count++;
          }
     }
}

Il codice di cui sopra stampa il valore di count: il loop while viene eseguito 10 volte, dopodichè la condizione diventa false e il flusso continua in modo lineare.

Il costrutto Do-While

Il linguaggio di programmazione Java fornisce anche uno statement do-while:

do {
     statement(s)
} while (expression);

L’unica differenza tra il while e il do-while è che il secondo valuta l’espressione alla fine del loop, anziché all’inizio: questo implica che gli statement inclusi nel blocco do sono eseguiti almeno una volta. Vediamo l’esempio seguente:

class DoWhileDemo {
     public static void main(String[] args){
          int count = 1;
          do {
               System.out.println("Count is: " + count);
               count++;
          } while (count <= 11);
     }
}
Il costrutto for

Il costrutto for fornisce un modo compatto per iterare su un range di valori. La forma generale del for statement è la seguente:

for (initialization; termination; increment) {
    statement(s)
}

L’espressione di inizializzazione è eseguita una volta sola, quando il loop inizia. Quando l’espressione di terminazione vale false il loop termina. L’espressione di incremento è invocata ad ogni iterazione del loop e può incrementare o decrementare un valore. Vediamo qualche esempio:

// vengono stampati i numeri da 1 a 10
for (int i = 1; i <= 10; i++)
   System.out.println(i);
 
// conto alla rovescia da 10 a 1
for (int i = 10; i > 0; i--)
   System.out.println("Conto alla rovescia . . . " + i);
System.out.println("Decollo!");
Il costrutto foreach

Da Java 5 è disponibile il costrutto foreach che consente di ciclare gli elementi di un array o di qualsiasi cosa sia una collection o implementi l’interfaccia iterable: di questi aspetti ne parleremo meglio più avanti, per ora gustiamoci un esempio semplice:

public class ForEachDemo {
	public static void main(String[] args) {
		int[] elements = {1, 1, 2, 3, 5, 8, 13, 21};
		for (int element : elements) {
			System.out.println(element);
		}
	}
}

Vengono stampati in console gli elementi dell’array su linee separate. Il loop si legge: “per ogni element in elements“. Ovunque sia possibile usarlo è preferibile al ciclo for tradizionale, in quanto è conciso e chiaro.

Switch, break e continue
Switch

Il costrutto if/else diventa velocemente complesso e intricato se bisogna gestire molte alternative: in questo caso si utilizza lo statement switch, che è esattamente uguale a quello del C++. Vediamo un esempio:

Scanner in = new Scanner(System.in);
System.out.print("Seleziona un'opzione (1, 2, 3, 4) ");
int choice = in.nextInt();
switch (choice)
{
   case 1:
      . . .
      break;
   case 2:
      . . .
      break;
   case 3:
      . . .
      break;
   case 4:
      . . .
      break;
   default:
      // opzione non prevista
      . . .
      break;
}

Viene valutato il valore di choice ed eseguito il codice del case che fa match con tale valore. Se non si ha un match viene eseguito il codice nella clausola opzionale default, se presente.

Attenzione: dopo ogni clausola deve essere specificato lo statement break, che fa uscire dallo statement. In caso contrario tutte le opzioni a seguire della prima che ha fatto match vengono eseguite: questo è potenzialemnte causa di errore, dato che è facile dimenticare di inserire lo statement break.

Break

Lo statement break non è usato solo per lo switch: in generale consente di uscire da un costrutto iterativo, saltando il codice restante e le iterazioni successive. E’ spesso usato in un ciclo for quando la condizione di terminazione non è nota a priori, ad esempio nel caso si stia ricercando un valore all’interno di un array; in tal caso infatti una volta reperito il valore cercato non c’è necessità di continuare a iterare:

class BreakDemo {
    public static void main(String[] args) {
        int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076,
                              2000, 8, 622, 127 };
        int searchfor = 12;
        int i;
        boolean foundIt = false;
        for (i = 0; i < arrayOfInts.length; i++) {
            if (arrayOfInts[i] == searchfor) {
                foundIt = true;
                break;
            }
        }
 
        if (foundIt) {
            System.out.println("Found " + searchfor
                               + " at index " + i);
        } else {
            System.out.println(searchfor
                               + " not in the array");
        }
    }
}
Continue

Lo statement continue transferisce il controllo all’inizio del loop più interno che lo racchiude, tralasciando l’esecuzione del codice a seguire, le iterazioni successive vengono comunque eseguite:

class ContinueDemo {
    public static void main(String[] args) {
 
        String searchMe = "Mi manca davvero tanto il goto";
        int max = searchMe.length();
        int numA = 0;
 
        for (int i = 0; i < max; i++) {
            // mi interessano solo le lettere a minuscole
            if (searchMe.charAt(i) != 'a')
                continue;
 
            numA++;
        }
        System.out.println("Ho trovato" + numA + " lettere 'a' nella stringa.");
    }
}

L’obiettivo è contare il numero di volte che la lettera ‘a’ minuscola compare nella stringa searchMe. Con il ciclo for viene scorsa la stringa alla ricerca di ‘a’: se la lettera in posizione i all’interno della stringa searchMe è diversa da ‘a’ allora invoco il continue, che fa saltare il resto del codice (ovvero l’incremento di numA) e tornare all’inizio del ciclo che lo contiene (in questo caso il for).

Conclusioni

Oggi vi abbiamo tediato con costrutti che a tanti di voi saranno conosciuti, ma tuttavia per completezza abbiamo deciso di includerli in questo corso (altrimenti che corso completo di programmazione Java sarebbe stato? 🙂 ).

Avrete notato l’assenza del goto: è stato dichiarato anni fa arma di distruzione di massa e per questo motivo non è stato incluso nel linguaggio Java; in teoria con i costrutti break e continue non se ne dovrebbe sentire la mancanza! Anzi in verità li abbiamo citati per amor di conoscenza, ma in generale il loro utilizzo non è particolarmente consigliato: evitarli se possibile.

Esistono anche versioni di break e continue che possono saltare ad una label… no, questa non ve lo dico 🙂 !

Alla prossima puntata (che prometto essere molto meno noiosa 🙂 ).

Il corso continua con…

05 – Java introduzione a UML e diagrammi di classe.

By Manuele Piastra

Sono un Project Manager i cui skill tecnici sono focalizzati al momento sullo sviluppo di applicazioni JavaEE (application server IBM Websphere 7.0 utilizzando JSF (RichFaces), JPA (EclipseLink) ed EJB3) ed Android. Presso OmniaGroup ricopro il ruolo di Training Manager: seleziono il personale tecnico, mi occupo della sua crescita formativa organizzando Corsi e Workshop sia interni che esterni, molti dei quali hanno visto me come docente. Ho tenuto sette sessioni di un corso di formazione di 50 ore sulle tecnologie JavaEE su Application Server WebSphere IBM presso il nostro cliente principale, Coop Italia, dei cui sistemi informativi sono consulente di riferimento. Sono blogger su CoseNonJaviste, blog tecnico che si occupa di Android e Java. Consulta il mio Curriculum online per maggiori informazioni.

4 comments

  1. salve…io ho provato a fare un giochino dove si deve semplicemente rispondere a delle domande…ora c’è un modo per eseguirlo fuori da netbeans?? e se è si come faccio?? grazie

Comments are closed.