L'informatico di Schrödinger

cat
15Nov/10Off

Java: un primo approccio alla programmazione imperativa – Il flusso di esecuzione

Java (programming language)

Image via Wikipedia

Abbiamo visto come scrivere il nostro primo programma in Java.
Abbiamo fatto una breve digressione su cosa significa programmare ad oggetti.

Oggi vedremo, in modo molto rapido e senza soffermarci troppo sui dettagli, come gestire il flusso di esecuzione di un programma.

Ci occuperemo quindi del "cuore" imperativo di Java.

Quando necessario, come al solito verranno introdotti alcuni concetti con cui è necessario familiarizzare sin da subito per riuscire a ad avere un'idea di come si comporta il nostro linguaggio: ovviamente siamo alle prime lezioni e tutto verrà ripreso e approfondito a tempo debito.

Innanzitutto una premessa: Java è un linguaggio staticamente tipato.

Ciò significa che, a differenza di altri linguaggi come PHP (e a maggior ragione a differenza dai linguaggi funzionali), al programmatore è lasciato l'onere di definire il Tipo di ciascuna variabile che decide di usare al momento della sua dichiarazione. Abbiamo accennato brevemente cosa intendiamo per Tipo nel post sulla programmazione ad Oggetti ma riprendiamo brevemente tale concetto:

"In Java tutti gli oggetti hanno un Tipo (e tutti i tipi sono specializzazioni di Object - la classe da cui tutte le classi sono derivate per specializzazione): ciascuna classe definisce un Tipo e gli oggetti di tale classe sono istanze di quel tipo."

Esistono, inoltre, dei "Tipi primitivi": sono quelli utilizzati per definire i valori numerici (byte, short, int, long, float, double, char) e boleani (boolean): ovviamente poiché in Java tutto quello con cui ci troviamo a lavorare sono sostanzialmente oggetti (o così almeno dovrebbe essere) per questi tipi base sono definite anche le equivalenti classi, che al momento non useremo (Integer, Double, Float...).

Quindi riassumendo brevemente:

  • “tipato” vuol dire che ad ogni espressione viene assegnato un tipo, che rappresenta l'insieme di valori che l'espressione potrebbe assumere;
  • “staticamente” vuole dire che il tipo di ogni espressione deve essere noto al momento della compilazione.

In tal modo, il compilatore è in grado di controllare che tutte le operazioni (compresa, ad esempio, l'assegnazione) siano applicate ad operandi compatibili.
Questa fase della compilazione è chiamata appunto “type checking”.

Detto questo partiamo con due esempi auto esplicanti sull'uso delle variabili:

1
2
3
int pippo; //dichiara una variabile intera di nome pippo
 
int pippo = 2; //dichiara una variabile e gli assegna un valore (assegnamento)

Una variabile può essere vista come una cella di memoria, a cui diamo un identificativo (il nome della variabile, nel nostro caso "pippo") e che contiene un valore che può mutare (variare) nel tempo.

Il contenuto delle variabili durante l'esecuzione di un'programma rappresenta lo "stato" in cui si trova il nostro programma istante per istante.

Più operazioni possono essere racchiuse in un insieme logico definito "blocco" racchiudendole tra parentesi graffe. Ad esempio:

1
2
3
4
5
6
7
int pippo = 0;
{
   int pippo2  = 20;
   pippo2++;
}
System.out.println(pippo++);
System.out.println(pippo2); //Errore

In questo caso la variabile "pippo2" definita all'interno del blocco (che inizialmente vale 20 e poi viene incrementata) all'uscita del blocco viene rimossa dalla memoria:  l'incremento successivo al blocco modifica il valore della variabile definita esternamente a questo.

Questo comportamento, definito dalle regole di "scoping", ci dice in buona sostanza che, dati due blocchi annidiati - sia A quello esterno e B quello interno - una variabile definita in A è leggibile e modificabile in B mentre una variabile definita in B non è accessibile ad A e termina la sua vita una volta concluso il blocco B.
E' molto importante aver chiaro questo meccanismo poiché per controllare il flusso di esecuzione di un programma, ed in generale per programmare, il concetto di "blocco" è uno dei concetti cardine. Ovviamente ritorneremo sulle regole di scoping più nel dettaglio in momenti successivi, in particolare quando introdurremo le parole chiave public\private\protected (e in altri momenti).

Chiarito il concetto di blocco possiamo addentrarci nella presentazione di quelli che sono i classici costrutti di programmazione imperativa.

Condizionale:

1
2
3
4
5
if ( Guardia ) {
    blocco_comandi_1;
} else {
    blocco_comandi_2;
}

Il significato è chiaro: si controlla se il valore dell'espressione "Guardia" è soddisfatto (vale true) o meno (vale false) e si esegue il relativo blocco di istruzioni. Può essere contratto in:

1
if ( Guardia ) ? alternativa_1 : alterntativa_2;

Switch-case:

1
2
3
4
5
switch ( Guardia ) {
   case valore1 : blocco_comandi_1; break;
   case valore2 : blocco_comandi_2; break;
   default: blocco_comandi;
}

Anche in questo caso ci si presentano blocchi di codice la cui esecuzione varia a seconda del valore della "Guardia": la guardia deve essere una variabile di tipo int (intero) o char (carattere).

Ciclo For:

1
2
3
for(int i=0; i<soglia; i++){
   blocco_comandi;
}

I cicli servono per ripetere uno stesso blocco di istruzioni più volte: il ciclo di tipo "for" inizializza un contatore (i nel nostro caso) e lo incrementa ad ogni esecuzione sino a che soddisfa la condizione che abbiamo imposto (nel nostro caso quindi sinché il suo valore è minore di quello della variabile "soglia").

Ciclo While:

1
2
3
while ( Guardia ){
   blocco_comandi;
}

Il ciclo "while" si comporta come il precedentemente descritto ciclo di tipo "for": l'unica differenza, e non da poco, è che questo ciclo può non terminare.
Sostanzialmente si continua ad eseguire il blocco di comandi definito all'interno del ciclo finche la condizione espressa dalla guardia risulta soddisfatta. Ci si aspetta che, in qualche modo, all'interno del blocco di comandi si vada quindi a modificare la\le variabile\i su cui viene eseguito il controllo nella guardia.

Ciclo do-while:

1
2
3
do {
   blocco_comandi;
} while ( Guardia );

L'unica differenza dal ciclo "while" visto sopra consiste ne fatto che in questo caso il blocco di comandi viene eseguito sempre almeno una volta: nel while classico se la guardia è da subito falsa il blocco di comandi non viene eseguito, nel caso del do-while invece questo viene eseguito prima di testare la guardia.

Abbiamo quindi visto tutti i principali costrutti per il controllo del flusso di un programma in Java (e in buona parte dei linguaggi che hanno una sintassi C-like): prima di concludere è però necessario dare almeno un'idea di quali siano gli operatori applicabili ai tipi di dati primitivi. Ecco un breve riassunto.

Operatori Aritmetici

+ 	Addizione
- 	Sottrazione
*	Moltiplicazione
/ 	Divisione
%	Modulo

Operatori Unari

+ 	Più unario; indica un valore positivo (può essere omesso)
- 	Meno unario; nega il valore di un espressione
++  	Operatore di incremento
--    	Operatore di decremento
!     	Complemento logico; inverte il valore di un booleano

Operatori di Eguaglianza

==	Uguale a
!=	Diverso da
>	Maggiore di
>=	Maggiore o uguale a
<	Minore di
<=	Minore o uguale a

Operatori Condizionali

&& And
|| Or

Nel prossimo post inizieremo a lavorare con gli elementi presentati in questo articolo, introdurremo gli array e le stringhe e, infine, utilizzeremo queste prime nozioni per scrivere un programmino un poco più interessante del primo esempio che abbiamo incontrato.

Stay Tuned!

Enhanced by Zemanta
Comments (2) Trackbacks (0)
  1. Quindi alla fine del blocco, all’interno, pippo vale 21, mentre all’esterno alla fine vale 1?

    E se fosse:
    int pippo = 0;
    {
    pippo++;
    }
    pippo++;

    pippo varrebbe….. sia dentro che fuori 1?
    Speriamo sia così >.<

  2. Corretto un refuso nell’esempio.
    No, nel tuo caso il contenuto di “pippo” fuori dal blocco più interno sarebbe 2 poiché tale variabile è stata dichiarata nel blocco principale e quindi non viene deallocata al termine del primo incremento e relativa uscita dal blocco interno.
    Al contrario se, come nell’esempio corretto, provi ad accedere una variabile definita all’interno del blocco fuori da questo otterrai un errore.


Leave a comment

You must be logged in to post a comment.

Trackbacks are disabled.