Corso Java #5: cicli di iterazione e condizionali

DiMarco Nisticò

PUBBLICATO IL 1 Mag 2019 ALLE 15:00 - AGGIORNATO IL 11 Marzo 2020 ALLE 11:57

I cicli sono uno degli elementi più utilizzati in un qualsiasi linguaggio di programmazione.

Già quando abbiamo approfondito l’argomento nel linguaggio C++, abbiamo subito identificato cosa sono i cicli. Si tratta di porzioni di codice nel quale viene eseguita una (o anche più) istruzione ripetutamente (iterazione) oppure a seconda della condizione si esegue una determinata istruzione (condizionali). I cicli di iterazione e condizionali sono comuni a quasi tutti i linguaggi di programmazione e si suddividono in tal modo:

  • CICLI CONDIZIONALI: if-else e switch-case
  • CICLI DI ITERAZIONE : while, do-while e for

Cicli condizionali

Come già anticipato, i cicli condizionali permette di eseguire una parte di codice secondo una condizione dall’utente. I due più conosciuti sono l’if-else e il switch-case. Il primo si può tradurre con l’espressione “Se è vera la condizione, allora esegui questa istruzione” mentre il secondo è esprimibile con la frase “A seconda del caso, esegui l’istruzione associata”.

Il ciclo if-else

Vediamo un primo esempio di if-else:

public class Input {
	
	public static void main (String args[]) {
int a=1;
int b=2;
if (a<b){ System.out.println("Il numero minore tra i due è a");}
else {System.out.println("Il numero minore tra i due è b");}}

In questo caso abbiamo definito due variabili intere, inizializzate con due valori ben precisi. Nel ciclo if-else si dice che se il numero “a” è minore del numero “b”, allora si stampa il messaggio specificato, altrimenti se ne stampa un altro. Fin qui molto semplice. Però in questo caso il programma non tiene conto di eventuali variabili passate dall’utente. Introduciamo quindi un elemento che approfondiremo successivamente, ovvero il System.in. Si tratta di un oggetto della classe BufferedReader che permette di leggere gli input dati da tastiera. Proviamo dunque ad inserire questo elemento in un programma che contiene un ciclo if-else.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Input {
	
	public static void main (String args[]) throws NumberFormatException, IOException {
	
	int a;
	 BufferedReader in = new BufferedReader(
	 new InputStreamReader(System.in));
	 System.out.println("Inserisci il valore di a: ");
	 a = Integer.parseInt(in.readLine());
	if (a<0) {System.out.println ("Il valore di a non è valido");}
	else {System.out.println(a);}
}}

Con questo esempio vogliamo dare un’impronta più marcata al significato di ciclo condizionale. Nella prima parte di codice abbiamo semplicemente definito una variabile intera “a”, con valore dato dall’utente attraverso l’oggetto di tipo BufferedReader. La stringa a =Integer.parseInt(in.readLine()); semplicemente legge un qualsiasi input come singolo carattere. Infine nella seconda parte abbiamo inserito il ciclo vero e proprio, dove si dice che se il valore di “a” è minore di 0, allora viene segnalato che il valore di “a” non è valido. In caso contrario, viene stampato semplicemente il valore di “a”.

Spesso il ciclo if-else è caratterizzato dalla sola condizione if, in cui viene eseguita la sola istruzione nel caso in cui si verifichi la condizione imposta. Inoltre se abbiamo un ciclo del tipo if-else if e la condizione data dall’if è vera, il codice dell’else if non verrà mai eseguito, anche se la sua condizione risultasse vera.

If-else annidati

All’interno di un ciclo if-else si può inserire un altro ciclo if, definendo quindi un’ulteriore condizione.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Input {
	
	public static void main (String args[]) throws NumberFormatException, IOException {
	
	int a;
	 BufferedReader in = new BufferedReader(
	 new InputStreamReader(System.in));
	 System.out.println("Inserisci il valore di a: ");
	 a = Integer.parseInt(in.readLine());
	if (a<0) {if (a<2) System.out.println ("Il valore di a non è valido");}
	else {System.out.println(a);}
}}

Riprendiamo l’esempio precedente. In questo caso abbiamo aggiungo la condizione if (a<2). Dunque il ciclo deve soddisfare sia la condizione a<0 che a<2, altrimenti l’istruzione non viene eseguita e si passa all’istruzione dell’else, se presente. Un caso limite di questo programma è il valore 1 (considerando solamente valori interi), dato che soddisferebbe la seconda condizione ma non la prima, per cui il risultato sarebbe la stampa del numero 1.

Il ciclo switch-case

Il ciclo switch-case è un ciclo condizionale molto differente dall’if-else poiché l’utente inizialmente definisce una singola variabile e tramite il costrutto switch definisce diversi casi (corrispondenti ad istruzioni differenti) che può assumere la variabile in gioco. Ciò su cui però bisogna fare molta attenzione è che il ciclo switch-case stampa le istruzioni successive al caso che abbiamo indicato in fase di esecuzione. Dunque se ad esempio abbiamo un ciclo switch on 5 casi e noi indichiamo il numero 3, il programma stamperà le istruzioni del case 3, 4 e 5. Per evitare di eseguire più case si utilizza il costrutto break all’interno di un ciclo switch-case, per terminare l’esecuzione del programma alla fine di ogni case. Vediamo una delle applicazioni classiche del ciclo switch-case, ovvero la calcolatrice.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Calcolatrice{
	
	public static void main (String args[]) throws NumberFormatException, IOException {
	
	int a;
int b;
 BufferedReader in = new BufferedReader(
	 new InputStreamReader(System.in));
	 System.out.println("Inserisci il valore di a: ");
	 a = Integer.parseInt(in.readLine());
	 System.out.println("Inserisci il valore di b: ");
b = Integer.parseInt(in.readLine());
int c=0;
 System.out.println("Inserisci l'operazione da svolgere: ");
 c = Integer.parseInt(in.readLine());
switch (c) {
case 1: int somma=a+b;
System.out.print(somma);break;
case 2: int differenza=a-b;
System.out.print(differenza);
break;
case 3:int prodotto=a*b;
System.out.println(prodotto);break;
case 4:int rapporto=a/b;
System.out.println(rapporto);break;
}}}

In un primo momento si definiscono i due numeri su cui vogliamo svolgere una delle quattro operazioni elementari. In seguito creiamo l’oggetto di tipo BufferedReader che legge entrambe le variabili da tastiera come carattere, attraverso il metodo Integer.parseInt(in.readLine());. Infine creiamo il ciclo switch con i diversi casi che corrispondono alle quattro operazioni, inserendo un costrutto break dopo ogni case per evitare che il programma stampi operazioni non richieste.

Il programma è relativamente semplice da capire, però ci sono degli accorgimenti di cui bisogna tener conto. Uno di questi è che la variabile interessata del ciclo switch deve essere di tipo primitivo.

Cicli di iterazione

Passiamo ora ai cicli di iterazione, ovvero quei cicli che eseguono una o più istruzioni più di una volta finché la condizione è verificata. Di questa categoria fanno parte il while, do-while e for. Il primo si riassume nell’espressione “Mentre la condizione X è vera, esegui Y istruzioni”, il secondo si esprime con la frase “Esegui X istruzioni e se la condizione X è verificata, esegui di nuovo” e il terzo si può esprimere come “Per le seguenti condizioni, esegui Y istruzioni”. Alcuni di voi avranno notato che tra il while e il do-while c’è una certa somiglianza. In realtà a livello esecutivo sono leggermente differenti. Infatti mentre nel while la condizione viene verificata prima di eseguire le istruzioni, nel do-while la verifica avviene dopo. Ciò significa che nel primo caso può capitare che un’istruzione non venga mai eseguita poiché la condizione non si verifica mai mentre nel secondo caso il blocco di istruzioni viene eseguito almeno una volta e se rispetta la condizione viene eseguito nuovamente.

Analizziamo ora singolarmente i vari cicli.

Il ciclo while

Il ciclo while esegue un’istruzione fin tanto che la condizione è vera. Esegue di conseguenza un controllo a PRIORI della condizione. Vediamo la sintassi con un esempio.

import java.io.BufferedReader;
	import java.io.IOException;
	import java.io.InputStreamReader;
	public class CicloWhile {
	
		
		public static void main (String args[]) throws NumberFormatException, IOException {
		
		int a;
	 BufferedReader in = new BufferedReader(
		 new InputStreamReader(System.in));
		 System.out.println("Inserisci il valore di a: ");
		 a = Integer.parseInt(in.readLine());
		 
		 while (a<10)
		 {System.out.println(a); 
		 break;}
}}

Tramite l’ormai noto System.in, passiamo il valore della variabile a, che verrà analizzato dal ciclo while nella condizione. Fintanto che tale valore risulta minore di 10, stampa a schermo il suddetto valore. Qui possiamo verificare come l’utilizzo del costrutto break sia fondamentale per l’esecuzione del programma. Infatti, se proviamo ad eseguire il codice senza inserire la stringa break;, il programma stamperà all’infinito il valore di a, nel caso rispetti la condizione, perché il valore è fisso e quindi se la condizione è vera una volta lo risulterà sempre. Quindi il break, in questo caso, risulta obbligatorio.

Facciamo un altro esempio sfruttando gli operatori logici.

import java.io.BufferedReader;
	import java.io.IOException;
	import java.io.InputStreamReader;
	public class CicloWhile {
	
		
		public static void main (String args[]) throws NumberFormatException, IOException {
		
		float a;
	 BufferedReader in = new BufferedReader(
		 new InputStreamReader(System.in));
		 System.out.println("Inserisci il valore di a: ");
		 a = Float.parseFloat(in.readLine());
		 
		 while (a<10&&a>8)
		 {System.out.println(a); 
		 break;}
}}

A livello concettuale l’esercizio è lo stesso, ma questa volta abbiamo introdotto gli operatori logici all’interno della condizione. L’espressione while (a<10&&a>8) significa che dovranno essere soddisfatte entrambe
le condizioni per poter eseguire le istruzioni nel ciclo. Inoltre abbiamo modificato il tipo primitivo della variabile da int a float, per aumentare all’infinito i valori che possiamo inserire. Se infatti per una variabile intera esisterebbe un solo numero capace di soddisfare le due condizioni, ovvero 9, nel caso di variabile float ci sono infinite possibilità.

Il ciclo do-while

Con una sintassi abbastanza simile, il ciclo do-while esegue il codice finché la condizione è vera, eseguendolo però almeno una volta anche se la condizione è falsa.

import java.io.BufferedReader;
	import java.io.IOException;
	import java.io.InputStreamReader;
	public class CicloDoWhile {
	
		
		public static void main (String args[]) throws NumberFormatException, IOException {
		
		float a;
	 BufferedReader in = new BufferedReader(
		 new InputStreamReader(System.in));
		 System.out.println("Inserisci il valore di a: ");
		 a = Float.parseFloat(in.readLine());
		 
		 do {System.out.println(a); 
		 break;}
		 while (a<10&&a>8);
}}

Adattando l’esempio precedente al caso del do-while, noteremo un aspetto davvero importante. Se provassimo ad eseguire il programma ed inserissimo il numero 7 come valore della variabile “a”, noteremo che tale valore sarà correttamente stampato a schermo, nonostante non rispetti le due condizioni. Questo proprio perché il ciclo do-while esegue un controllo a POSTERIORI della condizione.

Il ciclo for

Siamo arrivati all’ultimo argomento di questa quinta parte, ovvero il ciclo for. Questo ciclo di iterazione viene utilizzato spesso quando bisogna eseguire delle istruzioni che prevedono l’incremento di una variabile. Ad esempio si può utilizzare per stampare una serie di numeri, che segue delle specifiche regole oppure per realizzare delle sequenze ben precise.

La struttura è formata nel seguente modo:

for (inizializzazione; condizione; incremento) {
istruzioni;}

Un programma con ciclo for esegue esattamente tre passaggi. Il primo è l’inizializzazione di una variabile, indicata solitamente con “i” e valore iniziale 0. Successivamente viene eseguito il blocco d’istruzioni e la variabile “i” viene incrementata (o anche decrementata) di 1. Quindi si passa alla verifica della condizione. Se è vera, il blocco d’istruzioni viene nuovamente eseguito. L’iterazione si ferma quando la condizione diventa falsa, stampando a schermo il risultato ottenuto fino all’ultimo valore di “i” per cui la condizione risultava vera. Con il seguente esempio sarà sicuramente più chiaro.

import java.io.BufferedReader;
	import java.io.IOException;
	import java.io.InputStreamReader;
	public class CicloFor {
	
		
		public static void main (String args[]) throws NumberFormatException, IOException {
		
		int a;
	 BufferedReader in = new BufferedReader(
		 new InputStreamReader(System.in));
		 System.out.println("Inserisci il valore di a: ");
		 a = Integer.parseInt(in.readLine());
		 
		for (int i = 0; i<a; i++)
		{System.out.println(i);}
}}

Abbiamo sempre una variabile intera “a”, che passiamo noi da tastiera. Dunque definiamo un ciclo for con inizializzazione “i” a 0, condizione che “i” sia minore di “a” e l’incremento di “i”. L’istruzione prevede semplicemente la stampa della variabile “i”. In poche parole, il programma stampa in successione tutti i valori di “i” per cui vale la condizione i<a. Quindi se ad esempio il valore di “a” è 5, il risultato sarà 0 1 2 3 4. Nel dettaglio funziona così: inizialmente il valore di “i” è 0. Soddisfa la condizione? Se sì, si esegue l’istruzione e si incrementa di 1, quindi il valore di “i” adesso è 1. Con i=1 la condizione è verificata? Sì, dunque si può eseguire l’istruzione e incrementare ancora. Si prosegue così fin quando il valore di “i”, in questo caso 5, non rispetta più la condizione. Quindi alla fine ci vengono mostrati i valori di “i”.

Ora vi mostriamo un applicazione molto utile del ciclo for, ovvero la somma di n numeri interi fino ad un certo valore dato.

import java.io.BufferedReader;
	import java.io.IOException;
	import java.io.InputStreamReader;
	public class SommaNaturali {
	
		
		public static void main (String args[]) throws NumberFormatException, IOException {
		
		int a;
	 BufferedReader in = new BufferedReader(
		 new InputStreamReader(System.in));
		 System.out.println("Inserisci il valore di a: ");
		 a = Integer.parseInt(in.readLine());
		 int somma=0;
		 int i=0;
		for (i = 0; i<a; i++)
			{somma=i+somma;}
System.out.println(somma);
		}}

Questa volta è necessario inizializzare anche la variabile somma. Analizziamo passo passo l’esecuzione del ciclo for. Inizialmente la variabile “i” è 0 e la variabile somma è 0, quindi il risultato dell’istruzione è 0. Visto che i soddisfa la condizione, diventa 1 e quindi ora la variabile somma è 1 (1+0). A questo punto aumentiamo ancora “i”, che dunque diventa 2. Dato che ora la variabile somma è 1, il suo nuovo valore sarà 3 (2+1). A questo punto si prosegue fin quando “i” non soddisfa la condizione, come nel caso precedente.

Come avrete notato, le potenzialità dei cicli di iterazione e condizionali sono veramente infinite e permettono di creare dei piccoli programmi che eseguono delle operazioni di calcolo rapide, come la somma di n naturali o la stampa di una successione di numeri.

Di Marco Nisticò

Sviluppatore informatico, cerco sempre di stare al passo con i tempi in un mondo ormai circondato dalla tecnologia.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.