Il Lettore al termine di questo capitolo dovrà essere in grado di
Conoscere e saper utilizzare i vari operatori (unità 4.1).
Conoscere e saper utilizzare i costrutti di programmazione semplici
(unità 4.2, 4.3).
Conoscere e saper utilizzare i costrutti di programmazione avanzati
(unità 4.2, 4.4).
Unità didattica 4.1)
- Operatori di base
Di seguito è presentata una lista volutamente incompleta degli
operatori che Java ci mette a disposizione. Per alcuni di essi,
l’utilizzo è alquanto raro.
- Operatore d’assegnazione: =
- Operatori aritmetici :
somma +
sottrazione -
moltiplicazione *
divisione /
modulo %
L’unico operatore che può risultare non familiare al lettore, è
l’operatore modulo. Il risultato dell’operazione modulo tra due
numeri, coincide con il resto della divisione fra essi. Per esempio
5%3=2
10%2=0
100%50=0
Dalla sintassi del linguaggio C, Java ha ereditato anche altri
operatori unari (con un solo operando) che, oltre che svolgere
un’operazione, assegnano anche il valore del risultato ad una
variabile utilizzata nell’operazione:
somma e assegnazione +=
sottrazione e assegnazione -=
moltiplicazione e assegnazione *=
divisione e assegnazione /=
modulo e assegnazione %=
In pratica se abbiamo:
int i=5;
scrivere:
i=i+2;
è equivalente a scrivere:
i+=2;
- Operatori di pre e post-incremento
incremento di un’unità ++ (pre e post)
decremento di un’unità -- (pre e post)
Se vogliamo incrementare di una sola unità una variabile numerica,
posso equivalentemente scrivere:
i=i+1;
oppure:
i+=1;
ma anche:
i++;
oppure:
++i;
ottenendo comunque lo stesso risultato. Infatti, in tutti i casi,
otterremo che il valore della variabile i, è stato incrementato di
un’unità, ed assegnato nuovamente alla variabile stessa. Quindi
anche questi operatori svolgono due compiti (incremento ed
assegnazione). Parleremo di operatore di pre-incremento nel caso in
cui anteponiamo l’operatore d’incremento ++ alla variabile.
Parleremo invece, di operatore di post-incremento nel caso in cui
posponiamo l’operatore di incremento alla variabile. La differenza
tra questi due operatori "composti", consiste essenzialmente nelle
priorità che essi hanno rispetto all’operatore di assegnazione.
L’operatore di pre-incremento, ha maggiore priorità dell’operatore
di assegnazione =. L’operatore di post-incremento, ha minor priorità
rispetto all’operatore di assegnazione =.
Il seguente esempio rende visibile la differenza tra i due
operatori:
pre-incremento
x = 5;
y = ++x; si ha x=6 e y=6
post-incremento
x = 5;
y = x++; si ha x=6 e y=5
- Operatori bitwise:
NOT ~
AND &
OR |
XOR ^
shift a sinistra <<
shift a destra >>
shift a destra senza segno >>>
AND e assegnazione &=
OR e assegnazione |=
XOR e assegnazione ^=
shift a sinistra e assegnazione <<=
shift a destra e assegnazione >>=
shift a destra con riempimento di zeri e assegnazione >>>=
Tutti questi operatori binari, sono molto efficienti giacché
agiscono direttamente sui bit, ma in Java si utilizzano raramente.
L’operatore NOT ~ è un cosiddetto operatore unario, dato che si
applica ad un solo operando.
Gli operatori AND &, OR |, e XOR ^, si applicano a coppie di
operandi, e svolgono le relative operazioni logiche di conversioni
di bit riassunte nelle seguente tabella:
Operando1
Operando2
Op1ANDOp2
Op1OROp2
Op1XOROp2
0
0
0
0
0
0
1
0
1
1
1
0
0
1
1
1
1
1
1
0
Gli operatori di shift, provocano lo scorrimento verso una
direzione, dei bit della rappresentazione binaria di un certo
numero. Il numero dei bit da scorrere è rappresentato dall’operando
a destra dell’operazione. I bit che dopo lo scorrimento si trovano
al di fuori della rappresentazione binaria del numero, vengono
eliminati. I bit che invece "rimangono vuoti" vengono riempiti con i
valori 0 oppure 1 a seconda del caso. In particolare, lo scorrimento
a sinistra provoca un riempimento con i valori 0, per i bit lasciati
vuoti sulla destra della rappresentazione binaria del numero. Anche
lo scorrimento a destra senza segno riempie i bit lasciati vuoti con
degli 0. Lo scorrimento a destra con segno invece, provoca il
riempimento di 0 oppure di 1, a seconda che l’ultima cifra a
sinistra prima dello scorrimento (bit del segno) sia 0 oppure 1,
ovvero che la cifra prima dello scorrimento sia positiva o negativa.
Consideriamo i seguenti esempi:
byte a=35; byte b=-8;
a = a>>2; b = b>>1;
rappresentazioni binarie
00100011 35 11111000 -8
>>2 >>1
00001000 8 11111100 -4
int a = -1;
a = a>>>24;
11111111111111111111111111111111 -1
>>>24
00000000000000000000000011111111 255
Possiamo notare che l’operazione di scorrimento a sinistra equivale,
a dividere l’operando di sinistra, per 2 elevato l’operando situato
alla destra dell’operazione. Similmente, l’operazione di scorrimento
a destra equivale a moltiplicare l’operando di sinistra per 2
elevato l’operando situato sulla destra dell’operazione. Il
risultato viene arrotondato per difetto nelle operazioni con resto.
- Operatori relazionali o di confronto
Il risultato di queste operazioni è sempre un valore boolean, ovvero
true o false.
uguale a == tutti i tipi
diverso da != tutti i tipi
maggiore > solo i tipi numerici
minore < solo i tipi numerici
maggiore o uguale >= solo i tipi numerici
minore o uguale <= solo i tipi numerici
Notiamo che se confrontiamo due reference con l’operatore ==, il
risultato risulterà true se e solo se i due reference puntano allo
stesso oggetto, false altrimenti. Un classico errore che l’aspirante
programmatore commette spesso, è quello di scrivere = in luogo di
==.
- Operatori logico - booleani
I seguenti sono operatori che utilizzano solo operandi di tipo
booleano, ed il risultato è di tipo boolean:
NOT logico !
AND logico &
OR logico |
XOR logico ^
short circuit AND &&
short circuit OR ||
AND e assegnazione &=
OR e assegnazione |=
XOR e assegnazione ^=
E’ consuetudine utilizzare le versioni short circuit di AND ed OR.
Ad esempio, la seguente riga di codice, mostra come avvantaggiarsi
della valutazione logica di corto circuito per essere certi che il
risultato di una operazione di divisione sia valido prima di
valutarlo:
boolean flag = (a!=0 && b/a>10)
Affinché l’espressione tra parentesi sia vera, bisogna che entrambi
gli operandi siano veri. Se il primo tra loro è in partenza falso,
non ha senso andare a controllare la situazione dell’altro operando.
In questo caso addirittura sarebbe dannoso essendoci il rischio di
una divisione per zero. Quest'operatore short – circuit, a
differenza della sua versione tradizionale, fa evitare il secondo
controllo in caso di fallimento del primo. Equivalentemente
l'operatore short - circuit ||, nel caso la prima espressione da
testare risultasse verificata, convalida l'intera espressione, senza
nessun'altra (superflua) verifica.
- Concatenazione di stringhe con +
In Java l’operatore +, oltre che ad essere un operatore aritmetico,
è anche un operatore per concatenare stringhe. Per esempio il
seguente frammento di codice:
String nome = "James ";
String cognome = "Gosling";
String nomeCompleto = "Mr. " + nome + cognome;
farà in modo che la stringa nomeCompleto, avrà come valore "Mr.
James Gosling".
N.B.: se "sommiamo" un qualsiasi tipo di dato con una stringa, il
tipo di dato sarà automaticamente convertito in stringa, e ciò può
risultare molto utile.
- Priorità degli operatori
Nella seguente tabella sono riportati, in ordine di priorità, tutti
gli operatori di Java. Alcuni di essi non sono ancora stati
trattati.
Separatori
. [] () ; ,
da sx a dx
++ -- + - ~ ! (tipi di dati)
Da sx a dx
* / %
Da sx a dx
+ -
Da sx a dx
<< >> >>>
Da sx a dx
< > <= >= instanceof
Da sx a dx
== !=
Da sx a dx
&
Da sx a dx
^
Da sx a dx
|
Da sx a dx
&&
Da sx a dx
||
Da dx a sx
?:
da dx a sx
= *= /= %= += -= <<= >>= >>>= &= ^= |=
Il lettore non si spaventi! Non è necessario conoscere a memoria
tutte le priorità per programmare. Nell’incertezza, si possono
sempre utilizzare le parentesi tonde così come faremmo
nell’aritmetica tradizionale.