Un approccio a Java: I cicli - Introduzione


Ciao a tutti e bentornati! Sino ad ora, abbiamo parlato di variabili e di strutture di selezione, andando a considerare alcuni degli aspetti fondamentali di questi due concetti. Teoricamente, per scrivere qualsiasi tipo di programma, potrebbero essere sufficienti le nozioni viste sino ad ora. Sorge però un problema. Come possiamo assolvere compiti che richiedono la ripetizione sistematica di un blocco di codice? 

Introduzione

Supponiamo di avere il seguente esercizio: Scrivere un programma che stampi tutti i numeri naturali da 0 a n, dove n è dato.

Analizziamo velocemente la consegna. Ci viene richiesto di stampare una sequenza di numeri, che partano da 0 ed arrivino sino ad un numero, che ci viene fornito (per ora, non ci interessiamo del come). Ci si aspetta quindi un output del tipo 0, 1, ..., n.

La domanda che pongo ora è: con le conoscenze acquisite sino ad ora, siamo in grado di risolvere questo esercizio? 

Qualcuno, potrebbe dire sì, e magari proporre una soluzione come questa: 

public class Main{
    public static void main(String[] args){
        System.out.println(0);
        System.out.println(1);
        System.out.println(2);
    }
}

L'idea di questa soluzione è quella di supporre n noto e di scrivere tante istruzioni di stampa quanti i numeri da 0 a n. C'è però un grosso problema di fondo. Le soluzioni ai problemi devono essere quanto più generali possibili e funzionare con qualsiasi configurazione di variabili noi scegliamo.

Se ipotizzassimo che n da due diventa diecimila, questo codice, per quanto sintatticamente corretto, non assolverebbe più il suo compito, diventando quindi inutile. Dovremmo armarci di pazienza e scrivere diecimila istruzioni di stampa. Un lavoro a dir poco disumano.

Ovviamente, questo è un banale esempio dell'esigenza di eseguire sistematicamente blocchi di codice. Se riusciamo a trovare un meccanismo che ci permetta di ripetere un blocco di istruzioni, allora abbiamo risolto il nostro problema e possiamo fare codice ben più complesso con molto meno sforzo. Fortunatamente, non è necessario fare questo grande sforzo a livello implementativo, dal momento in cui Java ci mette a disposizione particolari costrutti detti cicli.

I cicli

Dopo questa introduzione, finalmente possiamo definire un cicli. SI può dire che:

Un ciclo è un insieme di istruzioni che possono essere eseguite ripetutamente sino a quando si verifica una certa condizione.

Capiamo quindi subito che, se da un lato non dobbiamo fare un sforzo implementativo che ci permetta di creare il meccanismo di ripetizione, dall'altro lato lo sforzo da fare riguarda ben due cose: l'individuazione della condizione l'individuazione delle istruzioni da ripetere.

Nella programmazione, si possono individuare fondamentalmente due gradi categorie di cicli: 

  • I cicli precondizionali
  • I cicli postcondizionali

Prima, però, è bene porre le basi di un corretto vocabolario.

Vocabolario: terminologia sui cicli

Definiamo guardia del ciclo, la condizione da verificare per far continuare il ciclo stesso.

Definiamo iterazione una singola ripetizione delle istruzioni del ciclo. 

Definiamo corpo del ciclo il gruppo di istruzioni che verranno ripetute.

Ciclo precondizionale

Definiamo un ciclo precondizionale quando il controllo della condizione viene effettuato prima dell'esecuzione del codice. Lo studente inesperto potrebbe pensare che questo fatto non sia per niente rilevante. Al contrario, riveste un'importanza cruciale. Questo perchè, nel momento in cui effettuo il controllo della condizione prima di eseguire il codice, potrei incorrere nel caso in cui la condizione sia falsa già prima della prima iterazione e quindi non eseguire proprio il corpo.

Vediamo un esempio, non in linguaggio Java ma in linguaggio naturale.

//programma per stampare i numeri da n a 0
n = -1;
finchè n > 0
    stampa n
    decrementa n

Vediamo che la variabile n è stata inizializzata a -1. La guardia del ciclo, però, richiede che n sia maggiore di zero. Per cui, all'inizio la guardia è già falsa e quindi il corpo del ciclo non viene proprio eseguito.

Chiaramente, questo è un caso particolare dove è presente proprio un errore di tipo logico. Significa che fondamentalmente abbiamo "pensato male". Non è l'unico caso. 

Ciclo postcondizionale

Definiamo un ciclo postcondizionale quando il controllo della condizione viene eseguito dopo aver eseguito il corpo del codice. Anche qui, ci sono pro e contro. Principalmente, decidiamo di usare un ciclo postcondizionale quando siamo assolutamente sicuri che abbiamo la necessità di eseguire almeno una volta il corpo del ciclo. Un classico esempio può essere quello di un menù che viene visualizzato sino a quando non si sceglie di uscire dall'applicazione.

esegui{
    mostra menù
    esegui operazione scelta
}finchè scelta diversa da uscita 

Capiamo un po' meglio come mai questa è la scelta migliore per questo tipo di problema. É la scelta migliore siccome noi abbiamo l'assoluta certezza del fatto che vogliamo mostrare almeno una volta il menù. 

Il ciclo a contatore

Vi è questa tipologia di ciclo che, a dire il vero, non può essere considerata una categoria a sè, in quanto sempre riconducibile ad una delle due precedenti. In realtà lo diventa de facto. Viene talmente usata che possiamo definirla quasi come una categoria.

Qual è la peculiarità. La presenza di un'entità detta contatore. Vediamo brevemente di cosa si tratta.

Un contatore è fondamentalmente una variabile, la cui funzione è contare

Spesso, ci serve contare quante iterazioni facciamo. Ricorriamo a questo tipo di concetto quando, per esempio, sappiamo a priori che vogliamo eseguire il corpo del ciclo un numero finito di volte. Se ci venisse chiesto di scrivere un programma che stampi l'intero alfabeto maiuscolo, sapremmo a priori che le lettere dell'alfabeto sono 26 e che quindi dovremo eseguire il corpo del nostro ciclo 26 volte. Vedremo più avanti degli esempi pratici di questi concetti.

Approfondimento: i loop infiniti

In informatica, è comunemente definito loop infinito un ciclo che non termina mai. Tipicamente, è associato ad errori di programmazione. In casi estremamente rari è necessario produrre di propria volotnà un loop infinito. 

Quando programmiamo dobbiamo sempre ricordarci che un ciclo dovrà sempre finire in qualche maniera. Un tipico esempio di loop potrebbe essere il seguente.

int n = 0;
finchè n > 0
    stampa n
    incrementa n

Vediamo chiaramente che questo ciclo non finirà mai, in quanto incrementiamo sempre n, allontanandoci sempre di più dallo zero. La guardia sarà sempre verificata e il ciclo non terminerà mai.

Queste situazioni vanno sempre evitate, in quanto sono problematiche da gestire.

Anche per questa volta è tutto. Vi invito a imparare bene questi concetti, che ci serviranno per scrivere codice. Vi invito inoltre a prendere ulteriore dimestichezza con quanto imparato sino ad ora. 

Sperimentate, mi raccomando wink

 
 
Alessio Mungelli

Alessio Mungelli

Computer Science student at UniTo (University of Turin), Network specializtion, blogger and writer. I am a kind of expert in Java desktop developement with interests in AI and web developement. Unix lover (but not Windows hater). I am interested in Linux scripting. I am very inquisitive and I love learning new stuffs.

 
 
 

Articoli correlati

Un approccio a Java: switch statement

Ciao a tutti e bentornati! Dopo una pausa, torniamo oggi con un'altra parte del corso introduttivo alla programmazione, parlando di switch statement, conosciuto anche come costrutto di selezione multipla.  Intuizione L'idea dello switch statement…

Un approccio a Java: Il ciclo while

Ciao a tutti e bentornati! Dopo aver fatto una breve, ma corposa, introduzione sui cicli, andiamo oggi a vedere finalmente le prime implementazioni che utilizzano quello che abbiamo definito ciclo precondizionale. In Java, come…

Un approccio a Java: strutture di selezione - casi d'uso

Ciao a tutti e bentornati! Sino ad ora ci siamo preoccupati di fare una carrellata quanto più completa riguardo i concetti fondamentali di cui abbiamo bisogno per approcciarci all'utilizzo delle…

Un approccio a Java: operatori booleani

La volta precedente, abbiamo ampiamente parlato delle variabili booleane, cercando di delineare quali siano le principali operazioni che si possono effettuare proprio a livello pratico.  Di tutti i casi esaminati, non abbiamo…

Un approccio a Java: le variabili booleane

Ciao a tutti e bentornati! La volta precedente, ho fatto un'introduzione alle strutture condizionali, definendo il loro funzionamento. Prima di poter dare qualche esempio pratico, è necessario chiarire in che modo ci…

Un approccio a Java: strutture condizionali

Ciao a tutti e bentornati! Le volte precedenti abbiamo introdotto il concetto di variabile, tentando di definire alcuni concetti basilari a riguardo.  Alcune situazioni fanno però intuire come il solo concetto…

Un approccio a Java: Le variabili - caso d'uso

Ciao a tutti amici e bentornati! Dopo l'introduzione fatta sulle variabili, cerchiamo di analizzare alcune criticità che si possono presentare in situazioni alquanto comuni. Partiamo quindi analizzando degli esempi pratici.  Esempio 1: divisione…

Linux per Principianti: I permessi

Nei precedenti articoli abbiamo fatto una breve introduzione al mondo Unix e nell'articolo successivo abbiamo parlato di comandi base per la gestione del file system. Oggi andremo a parlare di permessi. Come esempio prenderemo sempre…

Java Strutture Dati: Liste Concatenate

Con il 2020 andiamo ad esaminare un nuovo aspetto della programmazione: le strutture dati. Spesso capita a tutti di utilizzare strutture messe a disposizione dai vari linguaggi di programmazione. L'obiettivo sarà…

Java Algoritmi di Ordinamento: Selection Sort

Andiamo oggi ad analizzare in dettaglio un algoritmo di ordinamento non molto efficiente ma piuttosto utilizzato in diversi ambiti. Stiamo parlando del Selection Sort. Vediamo meglio in dettaglio. Intuizione L'idea alla base è quella…

Java algoritmi di ordinamento: Merge Sort

Andiamo oggi ad analizzare uno tra i migliori algoritmi di ordinamento: il Merge Sort. Detto anche algoritmo per fusione, fa parte della famiglia dei Divide and Conquer proprio come il Quick Sort. A differenza del…

Java algoritmi di ordinamento: Quick Sort

Bentornati in questa nostra panoramica sul mondo Java! Oggi andremo a parlare di un algoritmo di ordinamento tra i più celebri. Il Quick Sort. A differenza del precedentemente trattato Bubble Sort, Quick…

Clicky