SETTIMANA 3
Caratteri in una stringa
 Sappiamo già come estrarre sottostringhe da una stringa, con il metodo substring
 A volte è necessario estrarre ed elaborare sottostringhe di dimensioni minime, cioè di lunghezza unitaria
 una stringa di lunghezza unitaria contiene un solo carattere, che può essere memorizzato in una variabile di tipo char anziché in una stringa
 il tipo char in Java è un tipo di dato fondamentale come i tipi di dati numerici ed il tipo boolean, cioè non è una classe
Il tipo di dati char
(capitolo 4)
1
Caratteri in una stringa
2
Caratteri in una stringa
 Il metodo charAt della classe String restituisce il singolo carattere che si trova nella posizione indicata dal parametro ricevuto
 la convenzione sulla numerazione delle posizioni in una stringa è la stessa usata dal metodo substring
 La presenza del tipo di dati char non è strettamente necessaria in Java (ed è anche per questo motivo che non l’avevamo ancora studiato)
 infatti, ogni elaborazione che può essere fatta su variabili di tipo char potrebbe essere fatta su stringhe di lunghezza unitaria
String s = "John";
char ch = s.charAt(2); // ch contiene 'h'
 L’uso del tipo char per memorizzare stringhe di lunghezza unitaria è però importante, perché
 una variabile di tipo char occupa meno spazio in memoria di una stringa di lunghezza unitaria
 le elaborazioni su variabili di tipo char sono più veloci
 Una struttura di controllo che si usa spesso è l’elaborazione di tutti i caratteri di una stringa
3
Elaborazioni su variabili char
String s = "John";
for (int i = 0; i < s.length(); i++)
{ char ch = s.charAt(i);
// elabora ch
}
4
Caratteri e l'operatore +
 Come si può elaborare una variabile di tipo char?
 Una variabile di tipo char può anche essere confrontata con una costante di tipo carattere
 Un char può essere concatenato ad una stringa con l’operatore di concatenazione + (viene convertito in stringa, con le stesse regole della conversione dei tipi numerici)
 Se invece i due operandi di + sono entrambi caratteri
 una costante di tipo carattere è un singolo carattere racchiuso tra singoli apici (“apostrofo”)
char ch = 'x';
 Vengono automaticamente convertiti (“promossi”) in int
 L'operatore + indica una normale somma tra interi
 Il carattere può anche essere una “sequenza di escape”
char ch = '\u00E9'; // carattere 'è'
char nl = '\n'; // carattere di "andata a capo"
char a = 'a';
char b = 'b';
int intc = a + b;
char c = (char)(a + b);
System.out.println(“intc: ” + intc);
System.out.println(“c: “ + c);
 Una variabile carattere può essere stampata passandola a System.out.print o System.out.println
char ch = 'x';
System.out.println(ch); // stampa 'x' e va a capo
5
intc: 195
c: Ã
6
Sequenze di “escape”
 Proviamo a stampare una stringa che contiene delle virgolette
Hello, "World"!
Caratteri speciali e sequenze di “escape”
// NON FUNZIONA!
System.out.println("Hello, "World"!");
 Il compilatore identifica le seconde virgolette come la fine della prima stringa "Hello, ", ma poi non capisce il significato della parola World
 Basta inserire una barra rovesciata \ (backslash) prima delle virgolette all’interno della stringa
System.out.println("Hello, \"World\"!");
7
Sequenze di “escape”
8
Sequenze di “escape”
// FUNZIONA!
System.out.println("Hello, \"World\"!");
 Un’altra sequenza di escape che si usa è \n, che rappresenta il carattere di “nuova riga” o “andare a capo”
 Il carattere backslash all’interno di una stringa non rappresenta se stesso, ma si usa per codificare altri caratteri che sarebbe difficile inserire in una stringa, per vari motivi (sequenza di escape)
 Allora, come si fa ad inserire veramente un carattere backslash in una stringa?
System.out.println("*\n**\n***");
System.out.println("*");
System.out.println("**");
System.out.println("***");
 si usa la sequenza di escape \\
*
**
***
 Le sequenze di escape si usano anche per inserire caratteri di lingue straniere o simboli che non si trovano sulla tastiera
System.out.println("File C:\\autoexec.bat");
File C:\autoexec.bat
9
10
Escape e caratteri di controllo
Sequenze di “escape”
 Alcune sequenze di escape possono essere usate per  Ad esempio, per scrivere parole italiane con lettere accentate senza avere a disposizione una tastiera italiana
rappresentare dei caratteri di controllo
 Ovvero caratteri Unicode che non rappresentano System.out.println("Perch\u00E9?");
simboli scritti
 Ma che fanno parte integrante di un flusso di testo, Perché?
come tutti gli altri caratteri
 Queste sequenze di escape utilizzano la codifica standard Unicode ­ http://www.unicode.org per rappresentare i caratteri di tutti gli alfabeti del mondo con 4 cifre esadecimali (codifica a 16 bit, 65536 simboli diversi)
SEQ.ESCAPE
\n
\t
\b
\r
\f
11
NOME
newline
tab
backspace
return
formfeed
COD.UNICODE
\u000A
\u0009
\u0008
\u000D
\u000C
12
Caratteri di controllo
 I primi 32 caratteri nella codifica Unicode sono tutti caratteri di controllo
 Il cosiddetto insieme C0 di ASCII (e Unicode)
 Per chi e' interessato
Formattazione di numeri:
il metodo printf
• http://en.wikipedia.org/wiki/C0_and_C1_control_codes
• http://en.wikipedia.org/wiki/Control_character
 Vedremo altri importanti caratteri di controllo
 ETX (End­of­TeXt), immesso da tastiera con <CTRL>+C
• usato per interrompere l'esecuzione di un programma
 EOT (End­Of­Transmission, <CTRL>+D) e SUB (SUBstitute, <CTRL>+Z)
• Usati per segnalare la fine dell'input, ad esempio di un file 13
14
Formattazione di numeri
Formattazione di numeri
 Non sempre il formato standard per stampare numeri corrisponde ai nostri desideri
 Java fornisce il metodo printf, che ha più parametri espliciti
 Il primo parametro è una stringa di formato che contiene caratteri da stampare e specificatori di formato
double total = 3.50;
final double TAX_RATE = 8.5; // aliquota
d’imposta in percentuale
double tax = total * TAX_RATE / 100;
System.out.println(“Total: “ + total);
System.out.println(“Tax: “ + tax);
• Ogni specificatore di formato comincia con il carattere %
Total: 3.5
Tax: 0.2975
 Ci piacerebbe di più visualizzare i numeri
 Con due cifre decimali
Total: 3.50
 Incolonnati
Tax:
0.30
 I parametri successivi sono i valori da visualizzare secondo i formati specificati
System.out.printf(“Total:%5.2f”, total)
 Produce:
Total: 3.50
Spazio
15
16
Caratteri di fine riga
Formattazione di numeri
 Diversi sistemi operativi “capiscono” diversi caratteri di  Tipi di formato e modificatori di formato:
fine riga
 Sistemi Unix usano il carattere newline (o line­feed): \n
 DOS usa la sequenza carriagereturn­newline: \r\n
 Per essere sicuri che la fine della riga sia riconosciuta da qualsiasi sistema operativo possiamo usare il metodo printf con il formato %n
System.out.printf(“Total:%5.2f%n”, total)
 produce
17
Total: 3.50
Nuova riga
18
I dati in ingresso ai programmi
 I programmi visti finora non sono molto utili, visto che eseguono sempre la stessa elaborazione ad ogni esecuzione
 Il programma Coins1 rappresenta sempre il medesimo borsellino…
 se si vuole che calcoli il valore contenuto in un diverso borsellino, è necessario modificare il codice sorgente (in particolare, le inizializzazioni delle variabili) e compilarlo di nuovo
 I programmi utili hanno bisogno di ricevere dati in ingresso dall’utente
Ricevere dati in ingresso
19
20
La classe Scanner
L’input standard dei programmi
 Sfortunatamente, la classe InputStream non  Il modo più semplice e immediato per fornire dati in ingresso ad un programma consiste nell’utilizzo della tastiera
 altri metodi fanno uso del mouse, del microfono…
 Abbiamo visto che tutti i programmi Java hanno accesso al proprio output standard, tramite l’oggetto System.out di tipo PrintStream
 Analogamente, l’interprete Java mette a disposizione dei programmi in esecuzione il proprio input standard (flusso di input), tramite l’oggetto System.in di tipo InputStream
possiede metodi comodi per la ricezione di dati numerici e stringhe
 PrintStream ha invece il comodissimo metodo print
 Per ovviare a questo inconveniente, Java 5.0 ha introdotto la classe Scanner
 Un oggetto di tipo Scanner consente di leggere da qualsiasi flusso di ingresso (ad es. un file)
 Noi cominciamo ad usarlo per leggere dati in ingresso da tastiera ricevuti tramite l'oggetto System.in
21
22
Usare la classe Scanner
Sono due oggetti diversi!!
 Per leggere dallo standar input bisogna creare un oggetto di tipo Scanner, usando la sintassi consueta
Leggere l’input con la classe Scanner
Scanner in = new Scanner(System.in);
 Il parametro esplicito del costruttore di Scanner è System.in
 L'oggetto in di tipo Scanner è “agganciato” allo standard input
 Dato che la classe Scanner non fa parte del pacchetto java.lang, ma del pacchetto java.util, è necessario importare esplicitamente la classe all'interno del file java che ne fa uso import java.util.Scanner;
 Quando non si usa piu’ l’oggetto di classe Scanner e’ bene chiuderlo:
23
in.close();
24
I metodi nextInt e nextDouble Esempio
 Come si fa ad acquisire valori numerici da standard input?
 Numero intero: metodo int nextInt()
import java.util.Scanner;
public class Coins4
{ public static void main(String[] args)
{ Scanner in = new Scanner(System.in);
System.out.println("Quante lire?");
int lit = in.nextInt();
System.out.println("Quanti euro?");
double euro = in.nextDouble();
System.out.print("Valore totale in euro ");
System.out.println(euro + lit / 1936.27);
}
}
int number = in.nextInt();
 Numero in virgola mobile: metodo double nextDouble()
double number = in.nextDouble();
 Durante l’esecuzione del metodo (nextInt o nextDouble) il programma si ferma ed attende l’introduzione dell’input da tastiera, che termina quando l’utente batte il tasto Invio
 nextInt restituisce un valore numerico di tipo int
 NextDouble restituisce un valore numerico di tipo double
• cosa succede se l’utente non digita un numero intero (o un numero double) sulla tastiera ?? Provare!!
25
I metodi next e nextLine
26
Esempio
 Come si fa ad acquisire stringhe da standard input?
import java.util.Scanner;
 Parola  ovvero una stringa delimitata dai caratteri di spaziatura space (SP), tab (\t), newline (\n), carriage­return (\r)
 metodo String next()
public class MakePassword2
{ public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.println("Inserire il nome");
String firstName = in.nextLine();
System.out.println("Inserire il cognome");
String lastName = in.nextLine();
System.out.println("Inserire l’eta’");
int age = in.nextInt();
String initials = firstName.substring(0, 1)
+ lastName.substring(0, 1);
String pw = initials.toLowerCase() + age;
System.out.println("La password e’ " + pw);
}
}
String state = in.next();
 Riga
 (ovvero una stringa delimitata dai caratteri \n o \r):  metodo String nextLine(): String city = in.nextLine();
27
Scanner e localizzazione
 La classe Scanner prevede la possibilità di riconoscere numeri formattati secondo diverse “usanze locali”
 Nel corso noi useremo la convenzione anglosassone che prevede l’uso del carattere di separazione ‘.’ tra parte intera e parte frazionaria nei numeri in virgola mobile
 Per definire un oggetto Scanner che rispetta questa convenzione dovremo importare anche la classe Locale e scrivere
import java.util.Scanner;
import java.util.Locale;
...
Scanner in = new Scanner(System.in);
in.useLocale(Locale.US);
...
29
28
È tutto chiaro? …
1. Perché non si possono leggere dati in ingresso direttamente tramite System.in ?
2. Se in è un oggetto di tipo Scanner che legge da System.in e il nostro programma invoca
String name = in.next();
Qual è il valore di name se l’utente digita la seguente stringa?
John Q. Public
30
Realizzare classi
(Capitolo 3)
31
32
Scatole nere
Scatole nere
 Per molti guidatori
 Un’automobile è una scatola nera
 Non sanno come funziona
 Ma sanno come usarla
 Approccio alla programmazione
orientato agli oggetti
 Il software viene incapsulato in scatole nere (oggetti)
 Un ingegnere meccanico sa
progettare una automobile ma non
i moduli di controllo elettronico
 Non ne conosce il funzionamento interno
 Ma sa come usarli
 Scatole nere danno luogo ad incapsulamento
 I dettagli non importanti vengono nascosti
 Ma va identificato il concetto che meglio rappresenta una scatola nera: questo comporta astrazione
 Diversi livelli di astrazione
 Un utente di computer usa un programma costruito tramite oggetti senza sapere nulla di programmazione  Un programmatore può usare un oggetto senza conoscerne i dettagli di funzionamento
 Gli oggetti usati da un programmatore sono programmati da... altri programmatori
 Un oggetto contiene... altri oggetti
33
34
Progettare la classe BankAccount
 Vogliamo progettare la classe BankAccount, che descriva il comportamento di un conto corrente bancario
 Quali caratteristiche sono essenziali al concetto di conto corrente bancario?
 Possibilità di versare denaro
 Possibilità di prelevare denaro
 Possibilità di conoscere il saldo attuale
 Queste caratteristiche definiscono l'interfaccia pubblica della classe
Il progetto di una classe: BankAccount
35
36
Progettare la classe BankAccount
Definizioni di metodi
 Le operazioni consentite dal comportamento di un oggetto si effettuano mediante invocazione di metodi
 Dobbiamo definire tre metodi
public void deposit(double amount)
public double getBalance()
 La definizione di un metodo inizia sempre con la sua intestazione (o firma, o signature), composta da
 uno specificatore di accesso
public void deposit(double amount);
public void withdraw(double amount);
public double getBalance();
 Tali metodi consentono di
 depositare denaro nel conto account.deposit(1000);
account.withdraw(500);
 prelevare denaro dal conto
 conoscere il saldo double balance = account.getBalance();
• In questo caso public, altre volte vedremo private
 il tipo di dati restituito dal metodo (double, void...)
 il nome del metodo (deposit, withdraw, getBalance)
 un elenco di parametri, eventualmente vuoto, racchiuso tra parentesi tonde
• di ogni parametro si indica il tipo ed il nome
• più parametri sono separati da una virgola
37
38
Definizioni di metodi
Metodi di accesso e modificatori
 L'intestazione di un metodo è seguita dal corpo del metodo stesso, composto da
 un insieme di enunciati che specificano le azioni svolte dal metodo stesso
 racchiusi tra parentesi graffe
 Metodo d'accesso: accede ad un oggetto e restituisce informazioni senza modificarlo
 getBalance è metodo di accesso
 length della classe String è metodo di accesso
 getX, getY, getWidth, getHeight della classe Rectangle sono metodi di accesso
public void deposit(double amount)
{
//corpo del metodo
}
public double getBalance()
{
//corpo del metodo
}
 Metodo modificatore: altera lo stato di un oggetto
 deposit e withdraw sono metodi modificatori
 translate della classe Rectangle è un metodo modificatore
39
40
Ripasso: costruire oggetti  Abbiamo detto che per creare un nuovo oggetto di una classe si usa l’operatore new seguito dal nome della classe e da una coppia di parentesi tonde
Costruttori
new BankAccount();
 L’operatore new crea un nuovo oggetto e ne restituisce un riferimento, assegnabile ad una variabile oggetto del tipo appropriato
BankAccount account = new BankAccount();
account
41
BankAccount
42
I costruttori
I costruttori
 Sintassi:
 Nella realizzazione della classe BankAccount bisogna includere il codice per creare un nuovo conto bancario, ad esempio con saldo iniziale a zero.
 Per consentire la creazione di un nuovo oggetto di una classe, inizializzandone lo stato, dobbiamo scrivere un nuovo metodo, il costruttore della classe
public BankAccount()
{
//corpo del costruttore
}
tipoAccesso NomeClasse(TipoParametro nomeParametro,...)
{ //realizzazione del costruttore
}
 I costruttori hanno sempre lo stesso nome della classe
43
 Lo scopo principale di un costruttore è quello di inizializzare un oggetto della classe  I costruttori, come i metodi, sono solitamente pubblici, per consentire a chiunque di creare oggetti della classe
 La sintassi utilizzata per definire i costruttori è molto simile a quella dei metodi, ma
 il nome dei costruttori è sempre uguale a quello della classe
 i costruttori non restituiscono alcun valore e non bisogna neppure dichiarare che restituiscono void
Invocazione di costruttori
Una classe con più costruttori
 I costruttori si invocano soltanto con l’operatore new
 Una classe può avere più di un costruttore
 Ad esempio, definiamo un costruttore per creare un nuovo conto bancario con un saldo iniziale diverso da zero
new BankAccount();
 L’operatore new riserva la memoria per l’oggetto, mentre il costruttore definisce il suo stato iniziale  Il valore restituito dall’operatore new è il riferimento all’oggetto appena creato e inizializzato
 quasi sempre il valore dell’operatore new viene memorizzato in una variabile oggetto
44
public BankAccount()
{ // corpo del costruttore
// inizializza il saldo a 0
}
public BankAccount(double initialBalance)
{ // corpo del costruttore
// inizializza il saldo a initialBalance
}
BankAccount account = new BankAccount();
// ora account ha saldo zero
45
46
Una classe con più costruttori
Una classe con più costruttori
 Per usare il nuovo costruttore di BankAccount, bisogna fornire il parametro initialBalance
 Il compilatore effettua la risoluzione dell’ambiguità nell’invocazione di costruttori o metodi sovraccarichi
 Se non trova un costruttore che corrisponda ai parametri forniti nell’invocazione, segnala un errore semantico
BankAccount account = new BankAccount(500);
 Notiamo che, se esistono più costruttori in una classe, hanno tutti lo stesso nome, perché devono comunque avere lo stesso nome della classe
 questo fenomeno (più metodi o costruttori con lo stesso nome) è detto sovraccarico del nome (overloading)
 il compilatore decide quale costruttore invocare basandosi sul numero e sul tipo dei parametri forniti nell’invocazione
// NON FUNZIONA!
BankAccount a = new BankAccount("tanti soldi");
cannot resolve symbol
symbol : constructor BankAccount (java.lang.String)
location : class BankAccount
47
48
Sovraccarico del nome
Sovraccarico del nome
 Se si usa lo stesso nome per metodi diversi, il nome diventa sovraccarico (nel senso di carico di significati diversi…)
 questo accade spesso con i costruttori, dato che se una classe ha più di un costruttore, essi devono avere lo stesso nome
 accade più di rado con i metodi, ma c’è un motivo ben preciso per farlo (ed è bene farlo in questi casi)
 La libreria standard di Java contiene numerosi esempi di metodi sovraccarichi
public class PrintStream
{ ...
public void println(int n) {...}
public void println(double d) {...}
...
}
 Quando si invoca un metodo sovraccarico, il compilatore risolve l’invocazione individuando quale sia il metodo richiesto sulla base dei parametri espliciti che vengono forniti
• usare lo stesso nome per metodi diversi (che richiedono parametri di tipo diverso) sta ad indicare che viene compiuta la stessa elaborazione su tipi di dati diversi
49
50
Definizione di classe
 Sintassi:
tipoAccesso class nomeClasse
{ costruttori (intestazione e corpo)
metodi (intestazione e corpo)
variabili (campi) di esemplare
}
Definire una classe
 Le variabili di esemplare memorizzano lo stato di un oggetto
 La classe BankAccount deve avere un campo di esemplare che permetta di memorizzare il saldo di un oggetto di tipo BankAccount
51
Definire la classe BankAccount
52
È tutto chiaro? …
1. Come si può svuotare il conto bancario account public class BankAccount
{
//Costruttori
public BankAccount()
{ corpo del costruttore }
usando i metodi dell’interfaccia pubblica della classe?
2. Supponete di voler realizzare una più potente astrazione di conto bancario che tenga traccia anche di un numero di conto. Come va modificata l’interfaccia pubblica?
public BankAccount(double initialBalance)
{ corpo del costruttore }
//Metodi
public void deposit(double amount)
{ realizzazione del metodo }
public void withdraw(double amount)
{ realizzazione del metodo }
public double getBalance()
{ realizzazione del metodo }
}
//Campi di esemplare
...
53
54
Lo stato di un oggetto
 Gli oggetti (quasi tutti…) hanno bisogno di memorizzare il proprio stato attuale, cioè l’insieme dei valori che  descrivono l’oggetto e  influenzano (anche se non necessariamente) il risultato dell’invocazione dei metodi dell’oggetto
Variabili di esemplare
 Gli oggetti della classe BankAccount hanno bisogno di memorizzare il valore del saldo del conto bancario che rappresentano
 Lo stato di un oggetto viene memorizzato mediante variabili di esemplare (o “variabili di istanza”, instance variables)
55
Dichiarare variabili di esemplare
Variabili di esemplare
 Sintassi:
 Ciascun oggetto (“esemplare”) della classe ha una propria copia delle variabili di esemplare
public class NomeClasse
{ ...
tipoDiAccesso TipoVariabile nomeVariabile;
...
}
 Scopo: definire una variabile nomeVariabile di tipo TipoVariabile, una cui copia sia presente in ogni oggetto della classe NomeClasse
 Esempio:
public class BankAccount
{ ...
private double balance;
...
}
56
account1
BankAccount
balance 1000
account2
BankAccount
balance 2000
 tra le quali non esiste nessuna relazione: possono essere modificate indipendentemente l’una dall’altra
57
58
Variabili di esemplare
Incapsulamento
 Così come i metodi sono di solito “pubblici” (public), le variabili di esemplare sono di solito “private” (private)
 Le variabili di esemplare private possono essere lette o modificate soltanto da metodi della classe a cui appartengono
 le variabili di esemplare private sono nascoste (hidden) al programmatore che utilizza la classe, e possono essere lette o modificate soltanto mediante l’invocazione di metodi pubblici della classe
 questa caratteristica dei linguaggi di programmazione orientati agli oggetti si chiama incapsulamento o information hiding
 Poiché la variabile balance di BankAccount è private, non vi si può accedere da metodi che non siano della classe (errore semantico segnalato dal compilatore)
/* codice interno ad un metodo che
non appartiene a BankAccount */
double b = account.balance; // ERRORE
balance has private access in BankAccount
 Si possono usare solo i metodi pubblici!
59
double b = account.getBalance(); // OK
60
Incapsulamento
Incapsulamento
 L’incapsulamento ha molti vantaggi, soltanto pochi dei quali potranno essere evidenziati in questo corso di base
 Il vantaggio fondamentale è quello di impedire l’accesso incontrollato allo stato di un oggetto, impedendo così anche che l’oggetto venga (accidentalmente o deliberatamente) posto in uno stato inconsistente
 Il progettista della classe BankAccount potrebbe definire (ragionevolmente) che soltanto un saldo non negativo rappresenti uno stato consistente per un conto bancario
 Dato che il valore di balance può essere modificato soltanto invocando i metodi deposit o withdraw, il progettista può impedire che diventi negativo, magari segnalando una condizione d’errore
 Se invece fosse possibile assegnare direttamente un valore a balance dall’esterno, ogni sforzo del progettista di BankAccount sarebbe vano
 Si noti che, per lo stesso motivo e anche per realismo, non esiste un metodo setBalance, dato che il saldo di un conto bancario non può essere impostato ad un valore qualsiasi!
61
62
È tutto chiaro? …
1. Si supponga di modificare la classe BankAccount in modo che ogni conto bancario abbia anche un numero di conto. Come si modificano i campi di esemplare?
2. Quali sono i campi di esemplare della classe Rectangle?
Realizzare costruttori e metodi
63
I metodi di BankAccount
64
I costruttori di BankAccount
 La realizzazione dei costruttori e dei metodi di BankAccount è molto semplice
 lo stato dell’oggetto (il saldo del conto) è memorizzato nella variabile di esemplare balance
 i costruttori devono inizializzare la variabile balance
 quando si deposita o si preleva una somma di denaro, il saldo del conto si incrementa o si decrementa della somma specificata
 il metodo getBalance restituisce il valore del saldo corrente memorizzato nella variabile balance
 Per semplicità, questa realizzazione non impedisce che un conto assuma saldo negativo
public class BankAccount
{
public BankAccount()
{
balance = 0;
}
public BankAccount(double initialBalance)
{
balance = initialBalance;
}
...
}
65
66
Il costruttore predefinito
I metodi di BankAccount
 Cosa succede se non definiamo un costruttore per una classe?
 il compilatore genera un costruttore predefinito
 (senza alcuna segnalazione d’errore)
public class BankAccount
{ ...
public void deposit(double amount)
{ balance = balance + amount;
}
 Il costruttore predefinito di una classe
 è pubblico e non richiede parametri
 inizializza tutte le variabili di esemplare
public void withdraw(double amount)
{ balance = balance - amount;
}
• a zero le variabili di tipo numerico
• a false le variabili di tipo boolean
• al valore speciale null le variabili oggetto, in modo che tali variabili non si riferiscano ad alcun oggetto
public double getBalance()
{ return balance;
}
private double balance;
67
L’enunciato return
 Sintassi:
}
68
La classe BankAccount completa
public class BankAccount
{ public BankAccount()
{ balance = 0;
}
public BankAccount(double initialBalance)
{ balance = initialBalance;
}
public void deposit(double amount)
{ balance = balance + amount;
}
public void withdraw(double amount)
{ balance = balance - amount;
}
public double getBalance()
{ return balance;
}
private double balance;
}
return espressione;
return;
 Scopo: terminare l’esecuzione di un metodo, ritornando all’esecuzione sospesa del metodo invocante
 se è presente una espressione, questa definisce il valore restituito dal metodo e deve essere del tipo dichiarato nella firma del metodo
 Al termine di un metodo con valore restituito di tipo void, viene eseguito un return implicito
 il compilatore segnala un errore se si termina senza un enunciato return un metodo con un diverso tipo di valore restituito
69
70
È tutto chiaro? …
1. Come è stato realizzato il metodo getWidth() della classe Rectangle?
2. Come è stato realizzato il metodo translate della classe Rectangle?
Parametri espliciti/impliciti
71
72
I parametri dei metodi
public void deposit(double amount)
{ balance = balance + amount;
}
 Cosa succede quando invochiamo il metodo?
Il riferimento null
account.deposit(500);
 L’esecuzione del metodo dipende da due valori
 il riferimento all’oggetto account
 il valore 500
 Quando viene eseguito il metodo, il suo parametro esplicito amount assume il valore 500
 esplicito perché compare nella firma del metodo
 A quale variabile balance si riferisce il metodo?
 si riferisce alla variabile che appartiene all’oggetto account con cui viene invocato il metodo
 account è il parametro implicito del metodo 73
74
Il riferimento null
Il riferimento null
 Una variabile di un tipo numerico fondamentale contiene sempre un valore valido (eventualmente casuale, se non è stata inizializzata in alcun modo)
 Una variabile oggetto può invece contenere esplicitamente un riferimento a nessun oggetto valido assegnando alla variabile il valore null, che è una parola chiave del linguaggio
 Diversamente dai valori numerici, che in Java non sono oggetti, le stringhe sono oggetti
 una variabile oggetto di tipo String può, quindi, contenere un riferimento null
String greeting = "Hello";
String emptyString = ""; // stringa vuota
String nullString = null; // riferimento null
int x1 = greeting.length(); // vale 5
int x2 = emptyString.length(); // vale 0
// nel caso seguente l’esecuzione del programma
// termina con un errore
int x3 = nullString.length(); // errore
BankAccount account = null;
 vedremo in seguito applicazioni utili di questa proprietà
 in questo caso la variabile è comunque inizializzata
75
76
Usare un riferimento null
 Una variabile oggetto che contiene un riferimento null non si riferisce ad alcun oggetto
 non può essere usata per invocare metodi
 Se viene usata per invocare metodi, l’interprete termina l’esecuzione del programma, segnalando un eccezione di tipo NullPointerException (pointer è un sinonimo di reference, “riferimento”)
77
Collaudare una classe
78
Usare la classe BankAccount
Usare la classe BankAccount
 Senza sapere come sia stata realizzata la classe BankAccount, siamo in grado di utilizzarla in un programma
 apriamo un nuovo conto bancario e depositiamo un po’ di denaro
 Trasferiamo denaro da un conto ad un altro
double amount = 500;
account1.withdraw(amount);
account2.deposit(amount);
 Calcoliamo e accreditiamo gli interessi di un conto
double initialDeposit = 1000;
BankAccount account = new BankAccount();
System.out.println("Saldo: " +
account.getBalance());
account.deposit(initialDeposit);
System.out.println("Saldo: " +
account.getBalance());
Saldo: 0
Saldo: 1000
double rate = 0.05; // interessi del 5%
double amount = account.getBalance() * rate;
account.deposit(amount);
79
Classi di collaudo
80
Esempio: utilizzo di BankAccount
 Usiamo la classe BankAccount per risolvere un problema specifico
public class BankAccountTester
{ public static void main(String[] args)
{ BankAccount acct = new BankAccount(10000);
final double RATE = 5;
// calcola gli interessi dopo il primo anno
double interest = acct.getBalance() * RATE / 100;
// somma gli interessi dopo il primo anno
acct.deposit(interest);
System.out.println("Saldo dopo un anno: "
+ acct.getBalance() + " euro");
// calcola gli interessi dopo il secondo anno
interest = acct.getBalance() * RATE / 100;
// somma gli interessi dopo il secondo anno
acct.deposit(interest);
System.out.println("Saldo dopo due anni: "
+ acct.getBalance() + " euro");
}
}
 apriamo un conto bancario, saldo iniziale 10000 euro
 sul conto viene accreditato un interesse annuo del 5% del valore del saldo, senza fare prelievi né depositi
 qual è il saldo del conto dopo due anni?
 BankAccount non contiene un metodo main
 Compilando BankAccount.java si ottiene BankAccount.class
 Ma non possiamo eseguire BankAccount.class
 Dobbiamo scrivere una classe di collaudo (o di test) che contenga un metodo main nel quale
 Costruiamo uno o più oggetti della classe da collaudare
 Invochiamo i metodi della classe per questi oggetti
 Visualizziamo i valori restituiti
81
È tutto chiaro? …
1. Quando eseguo BankAccountTester, quanti 82
Un programma con più classi
 Per scrivere semplici programmi con più classi, si possono usare due strategie (equivalenti)
 Scrivere ciascuna classe in un file diverso, ciascuno avente il nome della classe con estensione .java
oggetti di tipo BankAccount vengono costruiti? E quanti di tipo BankAccountTester?
• Tutti i file vanno tenuti nella stessa cartella
• Tutti i file vanno compilati separatamente
• Solo la classe di collaudo (contenente il metodo main) va eseguita
Nel compito
 Scrivere tutte le classi in un unico file
83
faremo così!!
• un file .java può contenere una sola classe public
• la classe contenente il metodo main deve essere public
• le altre non devono essere public (non serve scrivere private, semplicemente non si indica l’attributo public)
• il file .java deve avere il nome della classe public
84
Riassunto: progettare una classe
1. Capire cosa deve fare un oggetto della classe
 Elenco in linguaggio naturale delle operazioni possibili
2. Specificare l'interfaccia pubblica
 Ovvero, definire i metodi tramite le loro intestazioni
3. Documentare l'interfaccia pubblica
4. Identificare i campi di esemplare a partire dalle intestazioni dei metodi
5. Realizzare costruttori e metodi
 Se avete problemi a realizzare un metodo forse dovete riesaminare i passi precedenti
6. Collaudare la classe con un programma di collaudo
Materiale di complemento
(capitolo 3)
85
86
Categorie e cicli di vita delle variabili
Parametri impliciti e il riferimento this
 Per ora saltiamo questa sezione (3.7)
• Ne parliamo più avanti (capitolo 9)
 Per ora saltiamo questa sezione (3.8)
• Ne parliamo più avanti (capitolo 9)
87
88
Commentare l'interfaccia pubblica
 I commenti ai metodi sono importantissimi per rendere il codice comprensibile a voi ed agli altri!
 Java ha delimitatori speciali per commenti di documentazione
Commenti di documentazione
/**
Preleva denaro dal conto
@param amount importo da prelevare
*/
public void withdraw(double
amount)
{
//corpo del metodo
}
/**
Ispeziona saldo attuale
@return saldo attuale
*/
public double getBalance()
{
 @param nomeparametro per //corpo del metodo
descrivere un parametro esplicito }
 @return per descrivere il valore restituito dal metodo
89
90
Commentare l'interfaccia pubblica
 Inserire brevi commenti anche alla classe, per illustrarne lo scopo
/**
Un conto bancario ha un saldo
modificabile tramite depositi e prelievi
*/
public class BankAccount
{
...
}
 Usando commenti di documentazione in questo formato si può generare in maniera automatica javadoc NomeClasse.java
documentazione in html
 Genera un documento NomeClasse.html ben formattato e con collegamenti ipertestuali, contenente i commenti a NomeClasse
91
92
L’enunciato if
 Il programma precedente consente di prelevare tutto il denaro che si vuole
 il saldo balance può diventare negativo
Decisioni
(capitolo 5)
balance = balance - amount;
 È una situazione assai poco realistica!
 Il programma deve controllare il saldo ed agire di conseguenza, consentendo il prelievo oppure no
93
L’enunciato if
94
Tipi di enunciato in Java
 Enunciato semplice
if (amount <= balance)
balance = balance - amount;
balance = balance - amount;
 L’enunciato if si usa per realizzare una decisione ed è diviso in due parti
 una verifica
 un corpo
 Il corpo viene eseguito se e solo se la verifica ha successo
 Enunciato composto
if (x >= 0) x=0;
 Blocco di enunciati
{ zero o più enunciati di qualsiasi tipo }
95
96
Un nuovo problema
La clausola else
 Proviamo ora ad emettere un messaggio d’errore in caso di prelievo non consentito
 Per realizzare un’alternativa, si utilizza la clausola else dell’enunciato if
if (amount <= balance)
balance = balance - amount;
if (amount > balance)
System.out.println("Conto scoperto");
if (amount <= balance)
balance = balance - amount;
else
System.out.println("Conto scoperto");
 Problema: se si modifica la prima verifica, bisogna ricordarsi di modificare anche la seconda (es. viene concesso un fido sul conto, che può “andare in rosso”)
 Problema: se il corpo del primo if viene eseguito, la verifica del secondo if usa il nuovo valore di balance, introducendo un errore logico  quando si preleva più della metà del saldo disponibile
 Vantaggio: ora c’è una sola verifica
 se la verifica ha successo, viene eseguito il primo corpo dell’enunciato if/else
 altrimenti, viene eseguito il secondo corpo
97
La clausola else
98
L’enunciato if
if (amount <= balance)
balance = balance - amount;
else
{ System.out.println("Conto scoperto");
balance = balance – OVERDRAFT_PENALTY;
}
 Sintassi:
if (condizione)
enunciato1
if (condizione)
enunciato1
else
enunciato2
 Scopo: eseguire enunciato1 se e solo se la condizione è vera; se è presente la clausola else, eseguire enunciato2 se e solo se la condizione è falsa
 Spesso il corpo di un enunciato if è costituito da più enunciati da eseguire in sequenza; racchiudendo tali enunciati tra una coppia di parentesi graffe { } si crea un blocco di enunciati, che può essere usato come corpo if (amount <= balance)
{
99
balance = balance - amount;
System.out.println("Prelievo accordato");
}
100
È tutto chiaro? …
1. Perché nell’esempio precedente abbiamo usato la condizione amount <= balance e non la condizione amount < balance?
2. Qual è l’errore logico nell’enunciato seguente, e come lo si può correggere?
if (amount <= balance)
newBalance = balance – amount;
balance = newBalance;
Confrontare valori numerici
101
102
Confrontare valori
Operatori relazionali
 Le condizioni dell’enunciato if sono molto spesso dei confronti tra due valori
 Fare molta attenzione alla differenza tra l’operatore relazionale == e l’operatore di assegnazione =
if (x >= 0)
 Gli operatori di confronto si chiamano operatori relazionali
Attenzione: negli operatori costituiti
da due caratteri non
vanno inseriti spazi
intermedi
>
>=
Maggiore
Maggiore o uguale
<
<=
Minore
Minore o uguale
==
!=
Uguale
Diverso
a = 5;
// assegna 5 ad a
if (a == 5)
enunciato
// esegue enunciato
// se a è uguale a 5
103
104
Confrontare numeri in virgola mobile
 I numeri in virgola mobile hanno una precisione limitata ed i calcoli possono introdurre errori di arrotondamento e troncamento
 Tali errori sono inevitabili e bisogna fare molta attenzione nella formulazione di verifiche che coinvolgono numeri in virgola mobile
Confronto di numeri in virgola mobile
double r = Math.sqrt(2);
double x = r * r;
if (x == 2)
System.out.println("OK");
else
System.out.println("Non ci credevi?");
105
106
Confrontare numeri in virgola mobile Confrontare numeri in virgola mobile
 Affinché gli errori di arrotondamento non influenzino la logica del programma, i confronti tra numeri in virgola mobile devono prevedere una tolleranza
 Possiamo definire un metodo statico che verifichi l’uguaglianza con tolleranza
public class Numeric
{ public static boolean approxEqual(double x, double y)
{ final double EPSILON = 1E-14;
double xyMax = Math.max(Math.abs(x),Math.abs(y));
return Math.abs(x - y) <= EPSILON * xyMax;
}
}
double r = Math.sqrt(2);
if (Numeric.approxEqual(r * r, 2))
System.out.println("Tutto bene...");
else
System.out.println("Questo non succede...");
 Verifica di uguaglianza tra x ed y (di tipo double):
| x ­ y | < ε con ε = 1E­14
 Scelta migliore se x,y sono molto grandi o molto piccoli
| x ­ y | < ε max(|x|,|y|) con ε = 1E­14
(questo valore di ε è ragionevole per numeri double)  Il codice per questa verifica è
final double EPSILON = 1E-14;
if ( Math.abs(x - y) <=
EPSILON*Math.max(Math.abs(x),Math.abs(y)) )
...
107
108
Confronto di stringhe
 Per confrontare stringhe si usa il metodo equals
if (s1.equals(s2))
 Per confrontare stringhe ignorando la differenza tra maiuscole e minuscole si usa
if (s1.equalsIgnoreCase(s2))
 Non usare mai l’operatore di uguaglianza per confrontare stringhe! Usare sempre equals
 Se si usa l’operatore uguaglianza, il successo del confronto sembra essere deciso in maniera “casuale”
 In realtà dipende da come è stata progettata la Java Virtual Machine e da come sono state costruite le due stringhe
Confronto di stringhe
Attenzione perché NON è un errore di sintassi
109
Confronto di stringhe
110
Confronto di stringhe
 Confrontando con l’operatore di uguaglianza due riferimenti a stringhe si verifica se i riferimenti puntano allo stesso oggetto stringa
String s1
String s2
String s3
s3 = s3 +
s1
s2
= "Stringa";
= s1;
= "String";
"a"; // s3 contiene "Stringa"
s3
 Il confronto s1 == s2 è vero, perché puntano allo stesso oggetto stringa
 Il confronto s1 == s3 è falso, perché puntano ad oggetti diversi, anche se tali oggetti hanno lo stesso contenuto (sono “identici”)
String s1
String s2
String s3
s3 = s3 +
= "Stringa";
= s1;
= "String";
"a";
String
Stringa
String
Stringa
111
112
Confronto di stringhe
Ordinamento lessicografico
 Confrontando invece con il metodo equals due riferimenti, si verifica se i riferimenti puntano ad stringhe con lo stesso contenuto
 Se due stringhe sono diverse, è possibile conoscere la relazione che intercorre tra loro secondo l’ordinamento lessicografico, simile al comune ordinamento alfabetico
 Il confronto lessicografico tra stringhe si esegue con il metodo compareTo
String s1
String s2
String s3
s3 = s3 +
= "Stringa";
= s1;
= "String";
"a"; // s3 contiene "Stringa"
if (s1.compareTo(s2) < 0)
 Il confronto s1.equals(s3) è vero, perché puntano a due oggetti String identici
 Nota: per verificare se un riferimento si riferisce a null, bisogna usare invece l’operatore di uguaglianza e non il metodo equals
 Il metodo compareTo restituisce un valore int  negativo se s1 precede s2 nell’ordinamento
 positivo se s1 segue s2 nell’ordinamento
 zero se s1 e s2 sono identiche if (s == null)
113
114
Confronto lessicografico
Confronto lessicografico
 Partendo dall’inizio delle stringhe, si confrontano i caratteri in posizioni corrispondenti, finché una delle stringhe termina oppure due caratteri sono diversi
 se una stringa termina, essa precede l’altra  Il confronto lessicografico genera un ordinamento simile a quello di un comune dizionario
 …con qualche differenza…  Tra i caratteri non ci sono solo le lettere
• se terminano entrambe, sono uguali
• i numeri precedono le lettere
• tutte le lettere maiuscole precedono tutte le lettere minuscole
• il carattere di “spazio bianco” precede tutti gli altri caratteri
 altrimenti, l’ordinamento tra le due stringhe è uguale all’ordinamento alfabetico tra i due caratteri diversi
c a r t a
c a s t a n o
lettere
uguali r precede s
 L’ordinamento lessicografico è definito dallo standard Unicode, http://www.unicode.org
carta precede castano
115
116
Confronto di oggetti
Confrontare oggetti
117
Ordinamento di oggetti
 Il metodo compareTo visto per le stringhe può essere applicato a molti altri oggetti, (ma non tutti perché non è definito nella classe Object)
 È compito di ciascuna classe definire in maniera opportuna il metodo compareTo, come fa la classe String, secondo una opportuna nozione di ordinamento
 Il metodo compareTo di una classe restituirà sempre un valore int  negativo se obj1 precede obj2 nell’ordinamento
 positivo se obj1 segue obj2 nell’ordinamento
 zero se obj1 e obj2 sono identici if (obj1.compareTo(obj2) < 0)
119
 Come per le stringhe, l’operatore == tra due variabili oggetto verifica se i due riferimenti puntano allo stesso oggetto, e non verifica l'uguaglianza tra oggetti
 Il metodo equals può essere applicato a qualsiasi oggetto, perché è definito nella classe Object, da cui derivano tutte le classi
 È compito di ciascuna classe ridefinire il metodo equals, come fa la classe String
 altrimenti il metodo equals di Object usa semplicemente l’operatore di uguaglianza
 Il metodo equals di ciascuna classe deve effettuare il confronto delle caratteristiche (variabili di esemplare) degli oggetti di tale classe
 Per ora usiamo equals solo per classi della libreria standard
 non facciamo confronti tra oggetti di classi definite da noi
118
È tutto chiaro? …
1. Qual è il valore di s.length() se s contiene (a) un 2.
riferimento alla stringa vuota “” (b) un riferimento alla stringa “ “ contenente solo uno spazio (c) il valore null ?
Quali di questi confronti hanno errori di sintassi? Quali hanno poca utilità dal punto di vista logico?
String
String
double
double
(a)
(d)
(g)
a
b
x
y
=
=
=
=
“1”;
“one”;
1;
3 * (1.0 / 3);
(b)
(e) a
a == “1”;
a == null;
a == b;
== x;
x – y == null;
(h)
(f)
(c)
a.equals(“”);
x == y;
x.equals(y);
120
Sequenza di confronti
 Se si hanno più di due alternative, si usa una sequenza di confronti
Alternative multiple
if (richter >= 8)
System.out.println("Terremoto molto forte");
else if (richter >= 6)
System.out.println("Terremoto forte");
else if (richter >= 4)
System.out.println("Terremoto medio");
else if (richter >= 2)
System.out.println("Terremoto debole");
else if (richter >= 0)
System.out.println("Terremoto molto debole");
else
System.out.println(“Numeri negativi non validi");
121
122
Sequenza di confronti
Sequenza di confronti
 Il codice seguente non funziona, perché stampa “Terremoto molto debole” per qualsiasi valore di richter
 Se si fanno confronti di tipo “maggiore di” si devono scrivere prima i valori più alti, e viceversa
 Se non si rendono mutuamente esclusive le alternative, usando le clausole else, non funziona
 se richter vale 3, stampa sia “Terremoto debole” sia “Terremoto molto debole”
if (richter >= 0)
// NON FUNZIONA!
System.out.println("Terremoto molto debole");
else if (richter >= 2)
System.out.println("Terremoto debole");
else if (richter >= 4)
System.out.println("Terremoto medio");
else if (richter >= 6)
System.out.println("Terremoto forte");
else
System.out.println("Terremoto molto forte");
if (richter >= 8)
// NON FUNZIONA!
System.out.println("Terremoto molto forte");
if (richter >= 6)
System.out.println("Terremoto forte");
if (richter >= 4)
System.out.println("Terremoto medio");
if (richter >= 2)
System.out.println("Terremoto debole");
if (richter >= 0)
System.out.println("Terremoto molto debole");
123
124
Diramazioni annidate
 Aliquote per categorie d’imposta federali (1992)
 Per semplicità usiamo il sistema fiscale americano e non quello italiano 
Diramazioni annidate
 Ci sono due livelli nel processo decisionale
 Prima dobbiamo scegliere lo stato civile
 Poi, per ciascuno stato civile, dobbiamo scegliere lo scaglione di reddito
125
126
Diramazioni annidate
Diramazioni annidate
 Usiamo due diramazioni annidate
 un enunciato if  all’interno del corpo di un altro enunciato if
if (status == SINGLE)
{ if (income <= SINGLE_BRACKET1)
...
else if (income <= SINGLE_BRACKET2)
...
else
...
}
else
{ if (income <= MARRIED_BRACKET1)
...
else if (income <= MARRIED_BRACKET2)
...
else
...
}
127
128
È tutto chiaro? …
1. L’enunciato if/else/else per la scala Richter verifica prima i valori più elevati. Si può invertire l’ordine delle verifiche?
2. Alcuni contestano l’applicazione di aliquote più elevate ai redditi più elevati perché dopo aver pagato le tasse si potrebbe rimanere con meno soldi pur avendo guadagnato di più. Dove è l’errore in questo ragionamento?
Il problema dell’else sospeso
129
Il problema dell’else sospeso
130
Il problema dell’else sospeso
 Nell’esempio seguente i livelli di rientro suggeriscono che la clausola else si riferisca al primo enunciato if
 ma il compilatore ignora i rientri!
 La regola sintattica è che una clausola else appartiene sempre all’enunciato if più vicino
double cost = 5; // prezzo per USA
if (country.equals("USA"))
if (state.equals("HI"))
cost = 10; // Hawaii più costoso
else
// NON FUNZIONA!
cost = 20;
// estero ancora più costoso
 L’esempio precedente svolge in realtà la funzione evidenziata dai rientri seguenti
double cost = 5; // prezzo per estero
if (country.equals("USA"))
if (state.equals("HI"))
cost = 10; // Hawaii più costoso
else
cost = 20; // USA ancora più costoso
 Il risultato è che gli stati esteri ottengono il prezzo più basso, e gli USA continentali il più alto! Il contrario di ciò che si voleva...
131
132
Il problema dell’else sospeso
 Per ottenere il risultato voluto, bisogna “nascondere” il secondo enunciato if all’interno di un blocco di enunciati, inserendo una coppia di parentesi graffe
 per evitare problemi con l’else sospeso, è meglio racchiudere sempre il corpo di un enunciato if tra parentesi graffe, anche quando sono inutili
Espressioni booleane
double cost = 5; // prezzo per USA
if (country.equals("USA"))
{ if (state.equals("HI"))
cost = 10; // Hawaii più costoso
}
else
cost = 20;
// estero ancora più costoso
133
134
Il tipo di dati booleano
Le variabili booleane
 Ogni espressione in Java ha un valore
 x + 10 espressione aritmetica, valore numerico
 x < 10 espressione relazionale, valore booleano
 Un’espressione relazionale può avere solo due valori:
 vero o falso (true o false)
 Il tipo di dati boolean, come tutti gli altri tipi di dati, consente la definizione di variabili
 A volte è comodo utilizzare variabili booleane per memorizzare valori di passaggi intermedi in cui è opportuno scomporre verifiche troppo complesse
 Altre volte l’uso di una variabile booleana rende più leggibile il codice
 Spesso le variabili booleane vengono chiamate flags (bandiere), perché possono assumere soltanto due valori, cioè trovarsi in due soli stati possibili: su e giù, come una bandiera
 I valori true e false non sono numeri, né oggetti, né classi: appartengono ad un tipo di dati diverso, detto booleano
 è un tipo fondamentale in Java, come quelli numerici
 Il nome deriva da quello del matematico George Boole (1815­1864), pioniere della logica
135
136
Metodi predicativi
 Così vengono chiamati metodi che restituiscono valori di tipo booleano
 Solitamente verificano una condizione sullo stato di un oggetto
 Solitamente iniziano con “is” oppure “has”
 La classe Character contiene metodi predicativi statici
 isDigit, isLetter, isUpperCase, isLowerCase
 La classe Scanner contiene metodi predicativi per verificare il contenuto dell’input:
 hasNextInt, hasNextDouble, …
 Metodi predicativi possono essere usati come condizioni di enunciati if
if (Character.isUpperCase(ch))
// esegue se il carattere ch è maiuscolo
137
Operatori booleani
138
Gli operatori booleani o logici
Gli operatori booleani o logici
 Gli operatori booleani o logici servono a svolgere operazioni su valori booleani
 Più operatori booleani possono essere usati in un’unica espressione
if (x > 10 && x < 20)
// esegue se x è maggiore di 10 e minore di 20
if ((x > 10 && x < 20) || x > 30)
 L’operatore && (and, e) combina due o più condizioni in una sola, che risulta vera se e solo se sono tutte vere
 L’operatore || (or, oppure) combina due o più condizioni in una sola, che risulta vera se e solo se almeno una è vera
 L’operatore ! (not, non) inverte il valore di un’espressione booleana  La valutazione di un’espressione con operatori booleani viene effettuata con una strategia detta cortocircuito (o valutazione pigra)
 la valutazione dell’espressione termina appena è possibile decidere il risultato
 nel caso precedente, se x vale 15, l’ultima condizione non viene valutata, perché sicuramente l’intera espressione è vera
139
Gli operatori booleani o logici
Gli operatori booleani o logici
A
B
A && B
true
true
true
true
false
false
false qualsiasi
false
A
B
true qualsiasi
false
true
false
false
 In un’espressione booleana con più operatori, la valutazione viene fatta da sinistra a destra, dando la precedenza all’operatore not, poi all’operatore and, infine all’operatore or
 L’ordine di valutazione può comunque essere alterato dalle parentesi tonde
A || B
true
true
false
A
true
false
140
if (!(x < 0 || x > 10))
// esegue se x è compreso tra 0 e 10,
// estremi inclusi
!A
false
true
if (!x < 0 || x > 10)
// esegue se x è maggiore o uguale a 0
141
È tutto chiaro? …
1. In quali condizioni il seguente enunciato 142
Leggi di De Morgan
 Stabiliscono un criterio per convertire un’espressione “negata” in una espressione “affermata”
visualizza “false”?
System.out.println(x > 0 || x < 0);
2. Riscrivere l’espressione seguente evitando di effettuare il confronto con il valore false
if (Character.isDigit(ch) == false)
 Gli operatori not vengono spostati su ciascuna delle espressioni coinvolte
 Gli operatori and e gli operatori or vengono scambiati
 Queste due espressioni sono equivalenti (abbiamo usato la seconda legge di De Morgan)
if (!(x < 0 || x > 10))
143
if ( x >0 && x <= 10 )
144
Materiale di complemento
(Capitolo 6)
145
146
L’enunciato switch
 Una sequenza che confronti un’unica variabile intera con diverse alternative costanti può essere realizzata con un enunciato switch
L’enunciato switch
int x;
int y;
...
if (x == 1)
y = 1;
else if (x == 2)
y = 4;
else if (x == 4)
y = 16;
else
y = 0;
int x;
int y;
...
switch (x)
{ case 1: y = 1; break;
case 2: y = 4; break;
case 4: y = 16; break;
default: y = 0; break;
}
147
148
L’enunciato switch
 Vantaggio: non bisogna ripetere il nome della variabile da confrontare
 Svantaggio: non si può usare se la variabile da confrontare non è intera
 Svantaggio: non si può usare se uno dei valori da confrontare non è costante
 Svantaggio: ogni case deve terminare con un enunciato break, altrimenti viene eseguito anche il corpo del case successivo! Questo è fonte di molti errori...
Consigli utili
149
150
Errori con operatori relazionali
Errori con operatori relazionali
 Alcune espressioni “naturali” con operatori relazionali sono errate, ma per fortuna il compilatore le rifiuta
 Il compilatore analizza l’espressione logica e trova due operatori di confronto, quindi esegue il primo da sinistra e decide che il risultato sarà un valore booleano
if (0 <= x <= 1)
// NON FUNZIONA!
if (0 <= x <= 1) x++; // NON FUNZIONA!
 Successivamente, si trova a dover applicare il secondo operatore relazionale a due operandi, il primo dei quali è di tipo boolean, mentre il secondo è di tipo int
if (0 <= x && x <= 1) // OK
if (x && y > 0)
// NON FUNZIONA!
if (x > 0 && y > 0)
// OK
operator <= cannot be applied to boolean,int
if (0 <= x <= 10) x++;
^
1 error
 Perché il compilatore le rifiuta?
151
Errori con operatori relazionali
Rientri e Tabulazioni
 Il compilatore analizza l’espressione logica e trova un operatore di confronto (che ha la precedenza sull’operatore booleano && ), il cui risultato sarà un valore di tipo boolean
 Successivamente, si trova ad applicare l’operatore booleano && a due operandi, il primo dei quali è di tipo int, mentre il secondo è di tipo boolean
operator && cannot be applied to int,boolean
if (x && y > 0) x++;
^
1 error
 Consigliamo anche di non usare i “caratteri di tabulazione”, che di solito generano un rientro di otto caratteri, eccessivo
153
Disposizione delle graffe
 Eventualmente lasciare su una riga da sola anche la graffa aperta
 Evitare questa disposizione
 è più difficile trovare la coppia!
 Decidere il numero ideale di caratteri bianchi da usare per ogni livello di rientro è molto arduo
 In questo corso consigliamo di usare tre/quattro caratteri
if (amount <= balance)
{ balance = balance - amount;
if (amount > 20000000)
{ System.out.println("Esagerato!");
}
}
if (x && y > 0) x++; // NON FUNZIONA!
 Incolonnare le parentesi graffe
152
if (...)
{ ...;
...;
}
if (...)
{
...;
...;
}
if (...) {
...;
...;
}
155
154