Sette grani di caffè contro lo stress

SETTE GRANI DI CAFFÈ CONTRO
LO STRESS
GUIDA PER SOSPETTI PROGRAMMATORI JAVA
di
Giuseppe Vincenzi
giuseppevincenzi.branded.me
2
Indice
1.
INTRODUZIONE
5
2.
IL KIT DELLO SVILUPPATORE JAVA
9
2.1.
QUESTO NON È UN CORSO UNIVERSITARIO
9
2.2.
UN LINGUAGGIO INTERPRETATO
9
2.3.
COS’È IL COMPILATORE JAVA?
10
2.4.
COME INSTALLARE LA JDK (“JAVA DEVELOPMENT KIT”)
12
2.5.
L’AMBIENTE DI SVILUPPO, LA TELA DEL PITTORE
21
2.6.
COME INSTALLARE L’IDE
21
2.7.
ESEGUIRE UN PROGRAMMA JAVA COMPILATO
23
3.
POLIMORFISMO: L’IPERURANIO INFORMATICO
37
3.1.
DALL’IPERURANIO DI PLATONE ALLA PROGRAMMAZIONE ORIENTATA AGLI
OGGETTI 37
3.2.
UNA PICCOLA LIBRERIA NELL’IPERURANIO
39
3.3.
IL POLIMORFISMO E L’EREDITARIETÀ
42
4.
COMINCIAMO A SPORCARCI LE MANI: IL PRIMO ESPERIMENTO
DELLA MOKA
47
4.1.
FACCIAMO UN CAFFÉ: LA CLASSE MOKA
47
4.2.
VARIABILI GLOBALI E METODI DI UNA CLASSE
47
4.3.
IL METODO “MAIN”
48
4.4.
ESPERIMENTO MOKA: SPECIFICHE
49
4.5.
COME CREARE UN NUOVO PROGETTO IN ECLIPSE
50
4.6.
ESPLORIAMO IL PACKAGE DI UN PROGETTO
57
4.7.
CREAZIONE DI UNA CLASSE
64
4.8.
DIALOGARE CON IL SISTEMA: LA CLASSE SYSTEM
69
4.9.
PORTIAMO A TERMINE L'ESPERIMENTO
70
4.10.
ESECUZIONE DI UNA CLASSE JAVA
73
5.
ANALISI GRAMMATICALE: COME ESPRIMERSI CORRETTAMENTE IN
JAVA 79
5.1.
SINTASSI E SEMANTICA DI UN LINGUAGGIO
79
5.2.
AVETE QUALCOSA DA DICHIARARE? LA VARIABILI IN JAVA
80
5.3.
OPERATORI SULLE VARIABILI
83
5.4.
OPERATORI ARITMETICI
83
5.5.
OPERATORI ARITMETICI DI ASSEGNAMENTO
84
5.6.
OPERATORI RELAZIONALI
85
5.7.
OPERATORI LOGICI
86
5.8.
OPERATORE TERNARIO
86
3
5.9.
GLI ARRAY IN JAVA
87
5.10.
ISTANZIARE UN OGGETTO: L’UTILIZZO DI “NEW”
88
5.11.
UNA SEQUENZA DI CARATTERI: LA CLASSE STRING
89
5.12.
MATRICI E ARRAY MULTIDIMENSIONALI
90
5.13.
COSTRUIRE UNA FRASE NEL LINGUAGGIO JAVA: LE ISTRUZIONI
91
5.14.
ISTRUZIONE CONDIZIONALE: IL COSTRUTTO IF... ELSE
93
5.15.
ISTRUZIONE CONDIZIONALE: IL COSTRUTTO SWITCH
94
5.16.
ISTRUZIONE RIPETITIVA: IL COSTRUTTO WHILE
95
5.17.
ISTRUZIONE RIPETITIVA: IL COSTRUTTO FOR
96
5.18.
ESPERIMENTOMOKASTRING
98
5.19.
ESPERIMENTOCERCAMOKA
99
6.
ELEMENTI DI SINTASSI PER DESCRIVERE IL NOSTRO IPERURANIO 103
6.1.
LE IDEE NELL’IPERURANIO: SINTASSI PER LA DESCRIZIONE DI UNA CLASSE
103
6.2.
SINTASSI PER LA DEFINIZIONE DI VARIABILI GLOBALI DI UNA CLASSE
105
6.3.
SINTASSI PER LA DEFINIZIONE DEI METODI DI UNA CLASSE
107
6.4.
METODO COSTRUTTORE
110
6.5.
EREDITARIETÀ DELLE CLASSI
111
6.6.
ESPERIMENTO LIBRERIA: SPECIFICHE
112
6.7.
CLASSE ASTRATTA
131
6.8.
INTERFACCE
132
6.9.
LA CLASSE OBJECT
141
6.10.
COME IMPLEMENTARE CORRETTAMENTE IL METODO EQUALS
142
7.
IMPARIAMO A GESTIRE I NOSTRI ERRORI
147
7.1.
EXCEPTION: L’IDEA DELL’ERRORE IN JAVA
147
7.2.
ESPERIMENTO DELLA DIVISIONE FRA NUMERI DECIMALI: SPECIFICHE
147
7.3.
ESPERIMENTO DELLA DIVISIONE FRA NUMERI DECIMALI: CONSIDERAZIONI SULLE
ECCEZIONI
148
7.4.
LA CLASSE EXCEPTION
151
7.5.
ELEMENTI DI SINTASSI: LE PAROLE CHIAVE “THROWS” E “THROW”
152
7.6.
ELEMENTI DI SINTASSI: BLOCCO TRY... CATCH... FINALLY
153
7.7.
CREAZIONE DI ERRORE SPECIFICI
155
8.
CONCLUSIONI
159
8.1.
ORA È IL MOMENTO DI APPROFONDIRE
159
4
1. Introduzione
Quando ero piccolo, mi piaceva aprire un Personal
Computer, come li chiamavamo allora, e digitare quei due
o tre comandi che mi avevano insegnato per veder
scorrere tutte quelle lettere e numeri, per me ancora senza
molto significato, davanti ai miei occhi: mi ricordava le
scene dei film americani dove, gli esperti di computer,
non avevano davanti a loro schermi con le finestre, o con
i colori, ma sempre schermi neri con lettere verdi che
scorrevano velocissime.
Ho sempre sognato di capire cosa significassero; ho
sempre sognato di guardare quegli schermi con gli stessi
occhi con cui li guardava l’attore americano, ovvero, con
gli occhi di chi ci capisce qualcosa, di chi ne ha il pieno
controllo. O almeno sa farlo credere bene, nel caso
specifico dell’attore americano.
Spinto da questa curiosità, ho cominciato a leggere
manuali sui Sistemi Operativi, ai miei tempi l’MS-DOS
andava molto di moda nei Personal Computer casalinghi
e non solo: capii però che il Sistema Operativo era già un
livello superficiale, rispetto al linguaggio parlato dalle
macchine. Mi resi conto che le macchine parlavano altre
lingue e, imparandole, si poteva descrivere un problema
al proprio PC, spiegargli la soluzione, e da quel momento
in poi lui avrebbe svolto un lavoro meccanico e ripetitivo
per noi.
5
Ed è così che ho cominciato a studiare i Linguaggi di
Programmazione. Conoscere un Linguaggio di
Programmazione è come saper scrivere uno spartito che
il nostro computer potrà eseguire tutte le volte che
vogliamo: l’esempio non è casuale, visto che io che scrivo
queste righe sono uno sviluppatore e sono un pianista.
E molte sono le cose in comune tra la programmazione e
l’arte: grazie alla programmazione, e a tutti gli strumenti
che i linguaggi vi mettono a disposizione, voi potrete ogni
volta creare un piccolo mondo, attorno al vostro
problema, analizzando e scrivendo tutte le varie soluzioni,
e mettendo poi a disposizione degli utenti tutto quello
che avete immaginato e realizzato. Praticamente è
esattamente quello che fa un compositore: grazie al
linguaggio musicale e ai suoi strumenti, lui riesce a
tradurre tutto il mondo che ha in testa, rispetto ad un
argomento che lo ha particolarmente colpito e ispirato, e,
cercate e trovate tutte le elaborazioni del tema, mette a
disposizione dei suoi ascoltatori il suo spartito, la sua
musica.
In questo piccolo manuale spesso citerò l’arte e la
filosofia per spiegare la programmazione: non ne siate
stupiti, perché l’utilizzo del pensiero e della creatività
nell’ingegneria del software sono indispensabili. Più di
quanto possiate immaginare.
6
La programmazione quindi è uno degli strumenti per
mettere in pratica la propria creatività, e proprio per
questo anche se non è e non sarà il vostro lavoro, o parte
di esso, comunque potrà interessarvi e diventare anche un
passatempo: programmare per me personalmente è un
po’ come fare bricolage. Io lo chiamo “Bricolage
digitale”: d’altronde come possiamo essere utili per
appendere una mensola in casa, possiamo esserlo anche
per scrivere un’applicazione che ci aiuta a fare i conti a
fine mese, o che ci aiuta a mettere in ordine le bottiglie
della nostra cantina, o ancora che può farci soltanto
divertire. E come vi diranno che la mensola che avete
attaccato voi è un po’ storta, e che sarebbe stato meglio
chiamare un esperto, così vi diranno che la vostra
applicazione per catalogare il vino non funziona
benissimo, e che era meglio comprare un software già
fatto: ma volete mettere la soddisfazione di vedere una
mensola attaccata al muro da voi con sopra le bottiglie
con un’etichetta stampata dal vostro piccolo software?
Impagabile.
Ed è però altrettanto vero che potrebbe diventare anche
il vostro lavoro: avere conoscenze di programmazione
potrebbe aprirvi nuove porte professionali e magari farvi
lanciare in una nuova avventura lavorativa. Studiamo i
concetti alla base dei Linguaggi di Programmazione e
facciamolo per tenere in allenamento il nostro cervello,
ma anche come un piccolo investimento: imparare un
linguaggio significa conoscere il seme, l’origine
dell’informatica che utilizziamo tutti i giorni, e questo ci
7
aiuterà anche a comprendere meglio gli strumenti con cui
operiamo quotidianamente.
Una leggenda narra che Baba Budan, un esponente
indiano della cultura Sufista, si trovava in Arabia Saudita:
conobbe il caffè e così decise di prendere sette chicchi e
portarli con sé nella sua isola di origine. Avrebbe potuto
direttamente portare con sé la bevanda o i grani già tostati
e magari tritati: invece investì sul futuro suo e della sua
isola, scegliendo i semi.
Tornato a casa, iniziò la coltivazione di caffè nel suo
paese, e ora ne è ancora uno dei maggiori produttori;
filosofia e informatica hanno legami antichi e inaspettati,
infatti, l’isola si chiama Java, e il caffè è lo stesso che
bevevano i fondatori del Linguaggio di Programmazione,
che descriveremo in questo manuale, e che, per questo,
decisero di battezzarlo con lo stesso nome.
8
2. Il kit dello sviluppatore Java
2.1. Questo non è un corso universitario
Questo manuale ha un obiettivo “professionalizzante”, e
per questo è estremamente orientato all’informatica “on
the road”: vorrà farvi divertire a sporcarvi le mani con il
linguaggio Java, come vi sporchereste le mani con l’argilla
ad un corso per la creazione di vasi in terracotta.
Proprio per questo ci tengo, come autore e informatico al
tempo stesso, a dire che questo manuale non si sostituisce
assolutamente ad un corso universitario o ai manuali
utilizzati per lo studio dell’ingegneria informatica: è un
manuale che fornisce le basi della programmazione Java,
cercando di farvi interessare all’argomento e magari
spingervi, dopo aver letto questo libro, ed aver portato a
termine gli esercizi che vi propongo, a comprare libri di
Tecniche di programmazione sempre più specifici
rispetto a quello che voi vorrete poi fare della vostra
conoscenza informatica.
2.2. Un linguaggio interpretato
Cominciamo a preparare gli strumenti del lavoro
dell’informatico. Fossimo stati pittori, vi avrei cominciato
a parlare di tavolozze, pennelli, colori e tele, ovvero di
quello che potremmo chiamare “Kit del pittore”: ma
9
siamo sviluppatori Java, quindi comincio con il parlarvi
del “Java Development Kit”, molto spesso abbreviato
in JDK e declinato al femminile, per motivi
grammaticalmente oscuri.
In questo kit si trovano tutta una serie di strumenti
fondamentali per uno sviluppatore Java, uno su tutti, è il
javac, ovvero il compilatore del codice Java.
2.3. Cos’è il compilatore Java?
Facciamo un piccolo passo indietro. Quando voi
scriverete il vostro codice java, lo farete creando dei file
che avranno l’estensione “.java” (Libro.java, Scaffale.java,
GestioneLibreria.java, ...) : questo file, per essere eseguito
da un Sistema Operativo ha bisogno di essere compilato,
ovvero tradotto nel dialetto comprensibile dalla macchina
su cui il software deve essere eseguito.
Immaginate che l’Italia è il Sistema Operativo, dove
quindi la lingua ufficiale è l’italiano.
Immaginate ora che un Linguaggio di Programmazione è
un dialetto parlato in una regione: per essere eseguito a
livello nazionale, c’è bisogno di compilarlo, ovvero di
tradurlo in italiano; in questo modo noi possiamo avere
molteplici linguaggi diversi, come se fossero dialetti di
10
diverse regioni, che potranno essere eseguiti sulla stessa
macchina Italia, proprio perché compilati in italiano.
Java ha una caratteristica in più rispetto ad altri linguaggi
di programmazione: è un linguaggio interpretato. Per
tornare al nostro esempio, è come se gli inventori di Java
avessero pensato ad un livello di astrazione maggiore
rispetto all’italiano, decidendo di compilare il linguaggio
Java in una lingua che è comune all’Italia e a tutti gli altri
paesi del mondo: è come se venisse compilato in latino.
A questo punto, una volta compilato, può essere eseguito
in tutti i paesi del mondo senza doverlo ogni volta
ricompilare: gli altri linguaggi in Italia sono compilati in
italiano, ma se volessero essere eseguiti in Francia,
dovrebbero essere ricompilati in francese, che è una
lingua di origine latina, come l’italiano.
Invece con il latino, basterà dare in mano un dizionario
latino ad un francese, e il codice in latino verrà eseguito
senza alcuna modifica necessaria.
Tornando all’informatica, il compilatore javac compila i
vostri file “.java” in file con estensione “.class”, che
contengono la traduzione in “bytecode” (nome
informatico del latino dell’esempio).
Il dizionario latino da avere nei diversi Sistemi Operativi
per interpretare il bytecode si chiama Java Virtual
Machine.
11
Riassumiamo dunque questa caratteristica fondamentale
di Java: i programmi scritti con questo linguaggio sono
indipendenti dalla piattaforma, ovvero possono essere
eseguiti su qualsiasi Sistema Operativo (DOS, Windows,
Unix, Linux, ...), previa installazione di una Java Virtual
Machine.
2.4. Come installare la JDK (“Java Development
Kit”)
Per installare la JDK bisogna seguire i seguenti passi:




12
Aprire un browser e andare sul sito del
distributore di Java (Oracle) all’indirizzo
http://www.oracle.com/technetwork/java/j
avase/downloads/index.html (figura 1)
Scegliere la “Java Platform (JDK) 7u17”
Fare attenzione, dopo aver scelto la “Java
Platform (JDK) 7u17”, a scaricare l’eseguibile
dell’installazione che si riferisce al Sistema
Operativo che state utilizzando sul vostro PC
(Windows, Linux, …) (figura 2)
Lanciate l’installazione e seguite le istruzioni che
vi appariranno sullo schermo (figura 3, figura 4,
figura 5, figura 6, figura 7, figura 8)
Figura 1
13
Figura 2
14
Figura 3
15
Figura 4
16
Figura 5
17
Figura 6
18
Figura 7
19
Figura 8
20
2.5. L’ambiente di sviluppo, la tela del pittore
Ora non ci resta che scaricare il nostro “ambiente di
sviluppo”, che in inglese si chiama “Integrated
Development Environment”, spesso abbreviato con
l’acronimo IDE.
Questo genere di software, come è facile immaginare,
non è altro che uno strumento che aiuta lo sviluppatore a
scrivere il codice più facilmente: è paragonabile ad un
Editor di testi, come Microsoft Word, che offre una serie
di strumenti che velocizzano la scrittura di un testo.
Quando scrivete una lettera, ad esempio, avete un
correttore automatico che vi evidenzia i potenziali errori:
l’IDE fa esattamente lo stesso lavoro, mettendovi in
evidenza errori nel codice, ed è solo un esempio dei
moltissimi strumenti che mette a disposizione.
2.6. Come installare l’IDE
Per la programmazione in Java viene spesso usato l’IDE
Eclipse: è un software open source sempre in costante
sviluppo e aggiornamento, distribuito da un consorzio
che si chiama “Eclipse Foundation”.
Per installare l’IDE bisogna seguire i seguenti passi:
21







22
Aprire un browser e andare sul sito all’indirizzo
http://www.eclipse.org/downloads/ (figura
9)
Scaricare “Eclipse IDE for Java EE
Developers”, sempre facendo attenzione alla
versione del vostro Sistema Operativo
Il file ZIP che avrete scaricato (figura 10),
basterà voi lo estraiate in una cartella a vostro
piacere sul disco rigido (figura 11, figura 12)
All’interno della cartella troverete un file che si
chiama “eclipse” (figura 13) e che, con un
doppio click, aprirà davanti a voi l’ambiente di
sviluppo (figura 14).
Vi si aprirà una popup che vi indicherà il
percorso proposto (una directory che, al primo
avvio verrà creata vuota) per il vostro
workspace (figura 15).
Alla prima apertura di Eclipse vi sarà proposta la
finestra di benvenuto: potete chiuderla cliccando
sulla ‘x’ accanto alla parola “Welcome” (figura
16).
Vi consiglio ora di cambiare la combinazione di
colori, per utilizzare quella più utilizzata dagli
sviluppatori:
 Aprite il menu Window e scegliete l’opzione
Preferences (figura 17)
 Nella finestra Preferences, nella parte
sinistra, estendete il menù General e dentro
cliccate l’opzione Appearance


Scegliete il tema “Classic” e cliccate su OK
(figura 18)
Vi apparirà una finestra (figura 19) che vi
chiederà di riavviare Eclipse: cliccate su Ok,
chiudete e riavviate Eclipse.
Adesso avete tutto il necessario (figura 20) per iniziare a
programmare in Java: avete la tela bianca sullo schermo e
i pennelli pronti accanto alla tavolozza.
2.7. Eseguire un programma Java compilato
Se in futuro vorrete far utilizzare i vostri software a
qualcuno, ovviamente questo utente non sarà obbligato a
installare tutto quello che avete voi: a lui basterà installare
il “Java Runtime Environment”, anche in questo caso
spesso abbreviato in JRE e declinato al femminile, per
motivi anche stavolta grammaticalmente oscuri.
Dopo l’installazione, sulla macchina del vostro utente
sarà disponibile la Java Virtual Machine e i comandi
necessari a eseguire i file java compilati, o più spesso i
cosiddetti file JAR.
Cos’è un file JAR? Altro non è che un file compresso,
esattamente come uno ZIP, che include più di un file java
compilato, magari tutti appartenenti ad un progetto.
23
Figura 9
24
Figura 10
25
Figura 11
26
Figura 12
27
Figura 13
28
Figura 14
29
Figura 15
30
Figura 16
31
Figura 17
32
Figura 18
33
Figura 19
34
Figura 20
35
36
3. Polimorfismo: l’iperuranio
informatico
3.1. Dall’iperuranio di Platone alla
Programmazione Orientata agli Oggetti
Java è un linguaggio di Programmazione Orientata agli
Oggetti (OOP, Object Oriented Programming): spiegare
cosa significa è molto semplice se facciamo ricorso alla
filosofia platonica.
Fedro, un giovane ateniese, appassionato di retorica,
passeggiando per le strade di Atene si incontra con
Socrate e con lui inizia a discorrere dell’arte di plasmare il
linguaggio naturale, di meta-linguaggio: questo incontro
verrà raccontato da Platone nel dialogo platonico
denominato proprio “Fedro”, e ambientato tra il 420 e il
410 a.C.
In questo dialogo Platone inserirà un concetto suo, che
ora analizzeremo molto in superficie e sarà attraverso
questo concetto filosofico che meglio capiremo il
concetto di Programmazione Orientata agli Oggetti.
Il concetto platonico che ci interessa analizzare è
l’Iperuranio: una zona al di là del cielo nella quale
risiedono le idee.
37
L’Iperuranio, in quanto posto al di là del limite estremo
del luogo fisico, ha una dimensione aspaziale, atemporale,
metafisica.
Ma cosa contiene dunque questo posto? Contiene le idee
di tutte le entità presenti sulla Terra, repliche imperfette
dell’idea di esse stesse.
Il rapporto tra le idee e le entità terrene può essere di
differente natura, secondo la concezione platonica; uno
dei rapporti in cui possono trovarsi l’idea e le sue entità
terrene è il rapporto di mimesi: secondo questo
rapporto gli oggetti terreni sono delle copie delle idee
immutabili e perfette.
Per esempio, se voi avete un albero (con la a minuscola)
nel parco sotto casa, dovete immaginare che quest’albero,
come tutti gli altri alberi del parco, non sono altro che
una copia, dell’Albero (stavolta con la A maiuscola),
intesa come idee perfetta e immutabile dell’albero: da un
punto di vista della terminologia, nel mondo del
linguaggio Java l’idea di Albero viene denominata classe,
mentre la copia, ovvero ognuno degli alberi del parco,
viene definita istanza.
E allora cosa sono gli oggetti, verso i quali il linguaggio
di programmazione è orientato? Gli oggetti sono
semplicemente le istanze di una classe: per questo da
adesso in poi, nel testo, quando useremo la parola
oggetto, indicheremo sempre il concetto di istanza di
una classe.
38
3.2. Una piccola libreria nell’iperuranio
Un programmatore Java vede tutto il mondo esattamente
come Platone: tutto quello che ha intorno è assimilabile a
una serie di classi con un livello di astrazione il più alto
possibile, e sempre replicabili.
Provate a immagine una libreria.
Di quali oggetti potreste immaginare composta la vostra
libreria?
Facciamo una prima divisione immaginando la libreria
composta da:








Lo scaffale del primo piano
Lo scaffale del secondo piano
Murder in Mesopotamia (Non c'è più scampo) di
Agatha Christie
Cards on the Table (Carte in tavola) di Agatha
Christie
Death on the Nile (Poirot sul Nilo) di Agatha
Christie
Dumb Witness (Due mesi dopo) di Agatha
Christie
The Picture of Dorian Gray (Il ritratto di Dorian
Gray) di Oscar Wilde
A Study in Scarlet (Uno studio in rosso ) di Sir
Arthur Conan Doyle
39
Cominciamo a lavorare sull’astrazione dei concetti
cercando di avvicinarci il più possibile all’iperuranio,
ovvero, all’idea della nostra libreria.
Lavoriamo sugli scaffali: ci sono due scaffali, per due
piani diversi, ma le caratteristiche dello scaffale sono le
stesse in tutte e due gli scaffali dei due piani diversi.
Questo mi suggerisce l’esistenza quindi di una classe
“Scaffale”, di cui abbiamo due repliche (istanze), che si
caratterizzano per la loro altezza da terra, riferendomi al
piano.
Quindi possiamo dire che l’oggetto Libreria è composto
da:

40
Oggetto “Libreria”
o Un set di oggetti “Scaffale”
o Murder in Mesopotamia (Non c'è più
scampo) di Agatha Christie
o Cards on the Table (Carte in tavola) di
Agatha Christie
o Death on the Nile (Poirot sul Nilo) di
Agatha Christie
o Dumb Witness (Due mesi dopo) di
Agatha Christie
o The Picture of Dorian Gray (Il ritratto di
Dorian Gray) di Oscar Wilde
o A Study in Scarlet (Uno studio in rosso)
di Sir Arthur Conan Doyle
Lavoriamo ora sui libri. Già avremmo facilmente
un’astrazione per autore:

Oggetto “Libreria”
o Un set di oggetti “Scaffale”
o Un set di oggetti “Libro di Agatha
Christie”
o Un set di oggetti “Libro di Oscar Wilde”
o Un set di oggetti “Libro di Sir Arthur
Conan Doyle”
Ma ovviamente non basta, possiamo fare molto meglio,
per esempio per genere:

Oggetto “Libreria”
o Un set di oggetti “Scaffale”
o Un set di oggetti “Libro di genere Giallo”
(di cui quelli di Agatha Christie e di Sir
Arthur Conan Doyle saranno istanze)
o Un set di oggetti “Libro di genere
Romanzo”
A questo punto vi verrà facile immaginare quale può
essere un’astrazione ancora migliore e forse conclusiva
per la nostra libreria:

Oggetto “Libreria”
o Un set di oggetti “Scaffale”
o Un set di oggetti “Libro”
41
Come potete vedere, lavorando sulla ricerca dell’idea di
libreria, nel senso platonico del termine, abbiamo trovato
un’astrazione che può descrivere sia la nostra libreria di
due piani con cinque libri sopra, che una libreria enorme
di 10 piani con mille libri catalogati.
Programmare a oggetti significa esattamente questo:
individuare le idee (le classi) dei componenti del sistema
che vogliamo realizzare, lavorando con le repliche, le
istanze degli oggetti astratti.
3.3. Il polimorfismo e l’ereditarietà
Finora abbiamo analizzato il ragionamento che può
portarci alla definizione del nostro sistema astratto:

Oggetto “Libreria”
o Un set di oggetti “Scaffale”
o Un set di oggetti “Libro”
Ma se ora volessimo proprio descrivere la nostra piccola
libreria, come dovremmo rapportarci rispetto agli oggetti
astratti che abbiamo disegnato? Dobbiamo cominciare ad
avvicinarci sempre più alla terminologia e alle specificità
del linguaggio Java: cominciamo a parlare nello specifico
di Polimorfismo. Cosa si intende per Polimorfismo del
linguaggio? Si intende il fatto che ogni classe può essere
istanziata e “estesa” in un altra classe che erediterà le
42
caratteristiche della classe estesa, ma ne avrà delle altre
specifiche.
Partiamo dai nostri scaffali descrivendo la classe, l’idea, di
Scaffale, elencando le sue caratteristiche, che nel
linguaggio Java chiameremo le variabili globali della
classe:

Classe “Scaffale”
o Lunghezza
o Larghezza
o Profondità
o Colore
o Altezza da terra
La nostra libreria quindi possiamo cominciare a
istanziarla; non faremo dunque solo una descrizione
astratta, ma scenderemo nello specifico delle
implementazioni:

Oggetto “Libreria”
o Un set di oggetti “Scaffale”
 Scaffale#1
 Lunghezza: 100cm
 Larghezza: 1cm
 Profondità: 30cm
 Colore: nero
 Altezzadaterra: 100cm
 Scaffale#2
 Lunghezza: 100cm
43
o
 Larghezza: 1cm
 Profondità: 30cm
 Colore: giallo
 Altezzadaterra: 150cm
Un set di oggetti “Libro”
Proviamo ora a descrivere la classe Libro, elencando le
sue caratteristiche, ovvero l’elenco delle sue variabili
globali di classe:

Classe “Libro”
o Titolo
o Autore
o Genere
o Protagonista
Ora è interessante immaginare anche una specificità
rispetto ai libri: un libro giallo, ad esempio, è una
cosiddetta “estensione” dell’idea di libro.
Cosa significa? Significa che un “Libro Giallo” eredita
tutte le caratteristiche di un “Libro” ma, ad esempio, ha la
specificità del “Colpevole”.
Potremmo sintetizzare scrivendo la classe e l’elenco delle
sue variabili globali:

44
Classe “LibroGiallo”
o Titolo
o
o
o
o
Autore
Genere
Protagonista
Colpevole
Ma, sfruttando il concetto proprio di Polimorfismo ed
ereditarietà potremo scrivere:

Classe “LibroGiallo” estende “Libro”
o Colpevole
E con questa descrizione affermiamo, molto più
sinteticamente, che un oggetto “Libro Giallo”, in quanto
estensione dell’oggetto “Libro”, avrà certamente tutte le
caratteristiche del “Libro”, senza per forza doverle
elencare, con in più la specificità del “Colpevole”.
Ed ecco che l’istanza della nostra libreria diventa:

Oggetto “Libreria”
o Un set di oggetti “Scaffale”
 Scaffale#1
 Lunghezza: 100cm
 Larghezza: 1cm
 Profondità: 30cm
 Colore: nero
 Altezza da terra: 100cm
 Scaffale#2
 Lunghezza: 100cm
45
o
46
 Larghezza: 1cm
 Profondità: 30cm
 Colore: giallo
 Altezza da terra: 150cm
Un set di oggetti “Libro”
 “Libro” #1
 The Picture of Dorian
Gray (Il ritratto di Dorian
Gray)
 Oscar Wilde
 Romanzo
 Dorian Gray
 “LibroGiallo” #2
 Murder in Mesopotamia
(Non c'è più scampo)
 Agatha Christie
 Giallo
 Hercule Poirot
 Il professor Leidner
 “LibroGiallo” #...
4. Cominciamo a sporcarci le mani:
il primo esperimento della Moka
4.1. Facciamo un caffè: la classe Moka
Affrontiamo ora un problema semplicissimo, giusto per
rompere il ghiaccio: faremo un programma in Java che
stamperà i passi per la preparazione di un caffè e poi,
acceso il fuoco, aspetterà che il caffè è pronto e ci
avviserà: ovviamente non ha alcuna utilità un software del
genere, se non quella di farci divertire a scrivere le nostre
prime istruzioni in Java.
Un software del genere potrebbe avere una sola classe
che potremmo caratterizzare come di seguito:

Oggetto “Moka”
o Variabili globali di classe
 Numero di tazze
4.2. Variabili globali e metodi di una classe
Immaginate che la nostra Moka non è una Moka
tradizionale, bensì è una di quelle elettroniche, con il tasto
per avviarla e che si spengono automaticamente quando il
caffè è pronto; il tasto della Moka, nel senso più generale
47
del termine, rappresenta un interruttore che fa partire una
funzionalità dell’oggetto: un po’ come per un lettore
MP3, ad esempio, avete un tasto che lancia la funzionalità
Play, uno che lancia la funzionalità Stop, e un altro ancora
che lancia la Riproduzione casuale.
Nel linguaggio Java le funzionalità di una classe vengono
denominate “metodi”; a questo punto siamo pronti a
schematizzare la nostra idea di Moka elencando le sue
caratteristiche e le sue funzionalità, ovvero le sue variabili
globali e i suoi metodi:

Oggetto “Moka”
o Variabili globali di classe
 Numero di tazze (Un numero intero
che indica il numero di tazze che
possono essere riempite dal caffè
prodotto dalla Moka)
o Metodi
 Avvia (Funzionalità che lancia il
riscaldamento della Moka, aspetta
che il caffè sia pronto, e spegne la
Moka avvertendo l’utente)
4.3. Il metodo “main”
Ogni classe Java può contemplare la funzionalità detta
main: come dice la parola stessa, è una funzionalità
48
“principale”, che conterrà una serie qualsiasi di
operazioni, che viene eseguita da un’istanza della classe
qualora questa dovesse rappresentare un oggetto che può
vivere di vita propria, che può “funzionare” in maniera
del tutto indipendente.
Immaginiamo la classe MokaTradizionale: lei non potrebbe
avere un metodo main, perché da sola non può svolgere
nessuna attività, al contrario del nostro esempio di Moka
elettronica che può da sola lanciare un processo di
funzionamento.
4.4. Esperimento Moka: specifiche
L’obiettivo di questo esperimento è creare una classe che
chiameremo EsperimentoMoka, con la sola funzionalità
main nella quale:




Stamperemo sul video (che in un IDE
chiameremo console) la sequenza di caratteri, che
da ora in poi chiameremo stringa: “Comincia
l’Esperimento Moka”;
Stamperemo sulla console la stringa: “Passo 1:
Apro la moka”;
Stamperemo sulla console la stringa: “Passo 2:
Metto il caffè”;
Stamperemo sulla console la stringa: “Passo 3:
Chiudo la moka”;
49



Stamperemo sulla console la stringa: “Passo 4:
Premo sul tasto Avvia”;
Stamperemo sulla console la stringa: “Passo 5: Il
caffè è pronto!”;
Stamperemo sulla console la stringa: “Fine
dell’Esperimento Moka”;
4.5. Come creare un nuovo progetto in Eclipse
Lanciate Eclipse e confermate il percorso del vostro
workspace.
Appena l’ambiente di lavoro è pronto, cliccate sul menù
File e scegliete la voce New: si aprirà un menù a tendina
contenente tutti i possibili tipi di progetto che si possono
creare con Eclipse.
Voi scegliete Project (figura 21): nella finestra che si
aprirà davanti a voi (figura 22) scegliete la tipologia Java
Project e cliccate su Next.
Qui (figura 23) possiamo scegliere:

50
Il nome da dare al progetto, che poi sarà il nome
di una cartella che Eclipse creerà nel percorso del
workspace sul nostro disco rigido: digitate
EsperimentoMoka;


La JRE (Java Runtime Environment, vedi
Capitolo “Il kit dello sviluppatore Java”) che
vogliamo usare: potremmo avere JRE diverse
installate sullo stesso PC;
Il Project layout: qui possiamo decidere se
dividere in cartelle separate i file con il codice
sorgente, ovvero quello scritto dallo
sviluppatore in Java (file con estensione .java), dai
file contenenti il codice compilato (file con
estensione .class). Generalmente si usa la
preselezione suggerita da Eclipse, ovvero la
separazione dei file in cartelle diverse.
Cliccate su Finish. A questo punto vi sarà suggerito di
aprire una nuova prospettiva da Eclipse (figura 24): in
pratica questo software ha la capacità di cambiare faccia
in base alla tipologia di progetto in lavorazione.
Accettate il cambio di prospettiva verso la “Java
Perspective”: il vostro ambiente di lavoro verrà
trasformato e adattato al meglio rispetto al tipo di
progetto su cui lavorerete.
Il vostro progetto è stato creato: nella sezione a destra
dello schermo “Package Explorer” vedrete apparire il
vostro progetto “EsperimentoMoka” (figura 25).
51
Figura 21
52
Figura 22
53
Figura 23
54
Figura 24
55
Figura 25
56
4.6. Esploriamo il package di un progetto
Ma che cos’è un package in Java? Provate a cliccare la
freccia
a
destra
del
nome
del
progetto
“EsperimentoMoka”: vi si aprirà il contenuto del
progetto.
Vedrete due linee:


Un’icona simile alle icone che identificano le
cartelle, con accanto il nome src
Una riga con scritto “JRE System Library”
Della seconda riga si parlerà più avanti; la prima riga
invece rappresenta la cartella “source”, ovvero la cartella
che conterrà tutti i file del codice sorgente: tutti i file del
codice sorgente possono essere organizzati, a loro volta,
in sottocartelle. Proprio queste sottocartelle in cui
vengono organizzati i file del codice sorgente si chiamano
package.
Per
esempio
creiamo
un
nostro
package
“esperimento”: per farlo cliccate con il tasto destro del
mouse sulla cartella src, scegliete la voce New, e dal menù
a tendina scegliete la voce package (figura 26).
Nella finestra che si aprirà per la creazione del package
(figura 27), scrivete il nome “esperimento” e cliccate
sul tasto Finish.
57
Figura 26
58
Figura 27
59
Vedrete comparire, nel Package Explorer, il vostro nuovo
package “esperimento” (figura 28).
Come avrete capito, si possono creare infiniti package per
meglio organizzare il nostro codice, e ovviamente si
possono creare package a più livelli: ad esempio ora noi
possiamo creare un sottopackage del package
“esperimento” che chiameremo “mokasemplice”.
Per farlo cliccate con il tasto destro del mouse sul
package “esperimento”, scegliete la voce New, e dal
menù a tendina scegliete la voce package.
Nella finestra che si aprirà per la creazione del package,
nel campo del nome troverete già scritto “esperimento”:
per creare il sottopackage, basterà scrivere
“esperimento.mokasemplice” (figura 29). Cliccate sul
tasto Finish e vederete comparire, nel Package Explorer,
il vostro nuovo package “esperimento.mokasemplice”
(figura 30).
Da un punto di visto fisico non stiamo facendo altro,
come avrete ormai capito, che creare delle cartelle e
sottocartelle nel nostro workspace: nel caso del mio
workspace (C:\Users\Giuseppe\workspace\), sul mio disco
rigido, avremo creato cartelle fino alla profondità:
C:\Users\Giuseppe\workspace\EsperimentoMoka\src\esperime
nto\mokasemplice
60
Figura 28
61
Figura 29
62
Figura 30
63
4.7. Creazione di una classe
A questo punto siamo pronti a creare la nostra classe in
Java.
Cliccate il tasto destro con il puntatore sul package
“mokasemplice”: dal menù contestuale scegliere New e
poi la voce Class (figura 31).
La finestra di dialogo che vi si apre davanti (figura 32) è
una delle finestre che userete di più nella vostra
esperienza di sviluppatori Java; in questa finestra potrete
selezionare tutte le caratteristiche principali di una classe,
queste sono quelle che per ora voi potrete comprendere:




64
Il percorso della cartella che contiene il codice
sorgente (“EsperimentoMoka/src”), sempre
ovviamente a partire dall’indirizzo fisico del
vostro workspace
Il package nel quale creare la Classe
(“esperimento.mokasemplice”)
Il nome della classe (“EsperimentoMoka”)
Potete chiedere a Eclipse di creare la classe
direttamente con il metodo main già pronto per
essere completato da voi, e per farlo basta
spuntare la voce “public static void
main(String[])”
Figura 31
65
Figura 32
66
A questo punto potete cliccare su Finish, e si aprirà
davanti a voi la classe che avete appena creato con il
metodo main auto-generato da Eclipse (figura 33): tra
l’altro nel corpo del metodo vedrete già una riga di
commento che vi segnala che il metodo è auto-generato
ed è ancora “da fare”, o come si dice in inglese, è ancora
in “TODO”.
67
Figura 33
68
4.8. Dialogare con il sistema: la classe System
Il nostro esperimento ci chiede di far stampare sulla
console una serie di stringhe definite.
Per stampare sulla console possiamo usare una classe
fornita con la JDK che si chiama System.
Questa classe, tra le altre cose, gestisce il flusso di dati che
arrivano dalla console (in termini tecnici lo chiamiamo
InputStream) e il flusso di dati che vanno verso la
console (in termini tecnici, come potrete immaginare,
vista la poca fantasia degli informatici, si chiama
OutputStream).
Questi due stream dovete immaginarli come variabili
globali della classe System; potremo usarli come oggetti
delle classi InputStream e OutputStream con i nomi
delle variabili di classe "System.in" e "System.out"; in
particolare, per il nostro esperimento, noi useremo un
metodo dell'oggetto System.out che rappresenta la
funzionalità che da la possibilità di scrivere una stringa
sulla console:

System.out
o Lista di metodi associati
 print(String)
 Metodo per scrivere il
contenuto
di
un
69

oggetto String (una
stringa)
println(String)
 Metodo per scrivere il
contenuto
di
un
oggetto String (una
stringa), spostando poi
il cursore sulla linea
successiva
4.9. Portiamo a termine l'esperimento
Ora abbiamo tutte le conoscenze per poter portare a
termine il nostro primo esperimento: è arrivato il
momento di scrivere il corpo del metodo main della
nostra classe EsperimentoMoka (figura 34):
package esperimento.mokasemplice;
public class EsperimentoMoka {
/**
* @paramargs
*/
public static void main(String[] args) {
System.out.println("Comincia l’Esperimento Moka");
System.out.println("Passo 1: Apro la moka");
System.out.println("Passo 2: Metto il caffé");
System.out.println("Passo 3: Chiudo la moka");
System.out.println("Passo 4: Premo sul tasto Avvia");
System.out.println("Passo 5: Il caffé è pronto!");
System.out.println("Fine dell’Esperimento Moka");
}
}
70
Alla luce di quanto ci siamo detti finora possiamo
comprendere tutto quello che c'è scritto in questo codice:
abbiamo l'invocazione del metodo usato per scrivere
sulla console ripetuta sette volte, come da specifiche
dell’esperimento.
Cosa cambia tra un'invocazione e un'altra? La differenza
sta solo nella stringa da stampare, ovvero in quello che si
chiama il parametro di un metodo, nello specifico
parliamo
del
parametro
del
metodo
“System.out.println(String s)”.
71
72
Figura 34
4.10. Esecuzione di una classe Java
Per eseguire una classe Java, è necessario che la classe
contenga la definizione di un metodo main: questa è
comprensibile alla luce anche di quanto ci siamo detti nel
paragrafo Il metodo main nel quale proprio ci siamo
detti che una classe può vivere di vita propria se contiene
questo metodo al suo interno, perciò sarà possibile
eseguire le funzionalità elencate nel suo metodo di
funzionamento principale.
Quando in Eclipse abbiamo aperta, nello spazio di lavoro
davanti a noi, una classe contenente un metodo main,
possiamo eseguirla cliccando sul tasto “Run”, ovvero
l’icona con il simbolo del “Play” su fondo verde (figura
35).
Prima di premerlo, diciamoci cosa significa eseguire e cosa
facciamo premendo questo tasto.
La prima cosa che il tasto Run farà sarà quella di
compilare il codice; come ci siamo detti nei primi
capitoli di questo manuale, la compilazione è un
passaggio obbligato e fondamentale nel linguaggio Java: la
compilazione della classe “EsperimentoMoka.java”
genererà un file di classe compilato contenente il
bytecode, che si chiamerà “EsperimentoMoka.class”.
Dopodiché sfrutteremo un componente della JDK che si
chiama “java.exe” che ha il compito di eseguire sulla
Java Virtual Machine il codice compilato: questo
73
componente aprirà la console e mostrerà all’utente il
risultato del programma Java in esecuzione.
Ma tutto questo che ci siamo detti, utilizzando un IDE
come Eclipse, sarà un lavoro sporco che il software farà
per noi: cliccando sul tasto Run a noi verrà direttamente
aperta la console in una finestra specifica che ci mostrerà il
risultato di quello che abbiamo scritto.
Cliccate dunque sul tasto Run e godetevi il caffè che
abbiamo preparato (figura 36): in base alla risoluzione
del vostro monitor potete allargare la console
posizionando il puntatore del mouse sui bordi della
console stessa e tenendo premuto il tasto destro (figura
37).
Con un doppio click sull’etichetta “Console” avrete il suo
contenuto a tutto schermo (figura 38); con un secondo
doppio click tornerete alla dimensione normale.
Ripensando ora alle specifiche dell’EsperimentoMoka,
otterrete proprio la stampa delle stringhe che abbiamo
inserito
come
parametro
nel
metodo
System.out.println(String s): godetevi il vostro primo
esperimento riuscito con successo, magari preparando e
bevendo un caffè vero.
Ve lo siete meritati.
74
Figura 35
75
Figura 36
76
Figura 37
77
Figura 38
78
5. Analisi grammaticale: come
esprimersi correttamente in Java
5.1. Sintassi e semantica di un linguaggio
Mi è capitato spesso, soprattutto con gli italiani all’estero,
di sentire persone che si esprimono in una lingua,
riuscendo anche a farsi capire, ma utilizzando male lo
strumento del linguaggio; non è raro sentire un italiano
parlare in francese, ordinare la sua cena in un ristorante,
magari commettendo molti errori grammaticali, o di
sintassi, ma essere comunque capiti dal cameriere. Anzi,
l’esempio che ho scelto forse non è dei migliori, perché i
francesi sono conosciuti per essere intransigenti sulla
sintassi: l’italiano dell’esempio rischia di non mangiare, o
di ripiegare su un fast food nei dintorni: per uno straniero
in Francia è decisamente più facile ordinare un
hamburger che una cena più complessa.
Con il linguaggio di programmazione si rischia lo stesso
errore: finora abbiamo usato Java come un italiano
all’estero da qualche mese usa il francese, ovvero, ci
siamo fatti capire ma senza avere una vera conoscenza
delle regola sintattiche e semantiche di Java.
Ma chiariamo già un concetto: che differenza c’è fra
semantica e sintattica di un linguaggio? Noi affronteremo
ora i due aspetti, parlando di Java, allo stesso tempo; è
necessario però sapere che per sintassi di un linguaggio
si intendono le regole che permettono di stabilire se
un’espressione (una frase) appartiene o meno ad un dato
linguaggio; per semantica invece si intendono le regole
79
che stabiliscono se le espressioni sono valide per un dato
linguaggio: è lo strumento chiave per l’interpretazione del
linguaggio stesso.
5.2. Avete qualcosa da dichiarare? La variabili in
Java
L’italiano che prima ha avuto grosse difficoltà a ordinare
la sua cena al ristorante in Costa Azzurra in Francia,
immaginate che abbia deciso di arrendersi e andare a
mangiare in un ristorantino della vicina Ventimiglia: in
questa città italiana vanno anche molti francesi, e non per
problemi con le ordinazioni, ma per godere del mercato
ligure del sabato.
Al rientro, sia i francesi, che il povero italiano finalmente
sazio, si possono trovare al casello della frontiera al
cospetto della Guardia di Finanza italiana che chiede se
abbiamo qualcosa da dichiarare.
Per esempio potremmo avere pacchi che possono
contenere qualsiasi cosa, certamente legale, ma che è
necessario dichiarare al momento del passaggio in
Francia.
Immaginate una variabile Java esattamente come uno
scatolo nel quale potete mettere qualsiasi cosa, ma che
deve necessariamente essere dichiarata prima di utilizzarla
“legalmente”.
80
Analizziamo la sintassi di una dichiarazione di variabile
in Java attraverso un esempio:
int numero;
Analizziamo la sintassi partendo da destra:



Simbolo ‘;’ (punto e virgola)
o Questo simbolo viene inserito alla fine
della dichiarazione;
numero
o Nome della variabile
int
o
Dichiarazione del tipo
 Ogni variabile ha un suo tipo
che ne contraddistingue il
contenuto
 In Java esistono i cosiddetti tipi
primitivi che sono tipi di base
del linguaggio Java
 Per ogni tipo di base esiste una
classe corrispondente nel
package java.lang che lo
ingloba, detta Classe Wrapper
81
Nome del Tipo
Contenuto
Classe
wrapper
byte
intero con segno a 8 bit
Byte
short
intero con segno a 16 bit
Short
int
intero con segno a 32 bit
Integer
long
intero con segno a 64 bit
Long
float
virgola mobile a 32 bit
singola precisione
Float
double
virgola mobile a 64 bit
singola precisione
Double
char
carattere singolo Unicode
intero senza segno a 16 bit
Character
boolean
Contiene un valore true o
false
Boolean
Vediamo ora altri esempi di dichiarazione di variabile e
analizziamone la sintassi:
int base, esponente;
int altezza = 10;
int larghezza = 20, profondità = 50;
Il primo è un esempio di dichiarazione di più variabili
dello stesso tipo; il secondo è la dichiarazione di una
variabile, definendone già il suo contenuto al momento
della dichiarazione; il terzo è un esempio di dichiarazione
di più variabili dello stesso tipo, con definizione del loro
contenuto.
82
5.3. Operatori sulle variabili
In Java per effettuare operazioni tra le variabili, si usano i
cosiddetti operatori: è un concetto identico a quello di
operazione nell’aritmetica.
Gli operatori sono funzioni che si applicano tra due o più
variabili dello stesso tipo (operandi), e danno origine ad
una variabile risultato, sempre ovviamente dello stesso
tipo degli operandi.
Proprio come nelle quattro operazioni della matematica,
esiste una priorità tra gli operatori di Java, qualora ce ne
fossero diversi nella stessa istruzione.
5.4. Operatori aritmetici
Questi tipi di operatori sono i seguenti:





Simbolo ‘*’
o Moltiplicazione tra variabili di tipo
numerico
Simbolo ‘/’
o Divisione tra variabili di tipo numerico
Simbolo ‘%’
o Operazione modulo, ovvero il resto
della divisione tra due variabili
numeriche
Simbolo ‘-’
o Sottrazione tra variabili di tipo numerico
Simbolo ‘+’
o Addizione tra variabili di tipo numerico
83
o
Concatenazione di variabili di tipo
carattere (char, Character, String, ...)
5.5. Operatori aritmetici di assegnamento





84
Simbolo ‘*=’
o Moltiplicazione tra variabili di tipo
numerico e assegnamento del risultato
alla variabile a sinistra dell’operatore
Simbolo ‘/=’
o Divisione tra variabili di tipo numerico e
assegnamento del risultato alla variabile a
sinistra dell’operatore
Simbolo ‘%=’
o Operazione modulo, ovvero il resto
della divisione tra due variabili
numeriche e assegnamento del risultato
alla variabile a sinistra dell’operatore
Simbolo ‘-=’
o Sottrazione tra variabili di tipo numerico
e assegnamento del risultato alla
variabile a sinistra dell’operatore
Simbolo ‘+=’
o Addizione tra variabili di tipo numerico
e assegnamento del risultato alla
variabile a sinistra dell’operatore

Concatenazione di variabili di tipo carattere
(char, Character, String, ...) e assegnamento del
risultato alla variabile a sinistra dell’operatore
5.6. Operatori relazionali
Tutti i tipi primitivi, tranne i booleani, possono essere
operandi degli operatori relazionali: in pratica viene
verificata una certa relazione tra i due tipi.
Gli operatori relazionali sono i seguenti:





Simbolo ‘>’
o Verifica che la variabile a sinistra del
simbolo sia maggiore di quella a destra
Simbolo ‘<’
o Verifica che la variabile a sinistra del
simbolo sia minore di quella a destra
Simbolo ‘>=’
o Verifica che la variabile a sinistra del
simbolo sia maggiore o uguale a quella a
destra
Simbolo ‘<=’
o Verifica che la variabile a sinistra del
simbolo sia minore o uguale a quella a
destra
Simbolo ‘==’
o Verifica che la variabile a sinistra del
simbolo sia uguale a quella a destra
85

Simbolo ‘!=’
o Verifica che la variabile a sinistra del
simbolo sia diversa da quella a destra
5.7. Operatori logici
Questi operatori vengono usati tra tipi booleani, e sono
una rappresentazione delle classiche funzioni logiche:






Simbolo ‘&&’
o Rappresenta l’operazione di AND logico
Simbolo ‘||’
o Rappresenta l’operazione di OR logico
Simbolo ‘&’
o Rappresenta l’operazione di AND logico
booleano
Simbolo ‘|’
o Rappresenta l’operazione di OR logico
booleano
Simbolo ‘^’
o Rappresenta l’operazione di XOR logico
Simbolo ‘!’
o Rappresenta l’operazione di NOT logico
5.8. Operatore ternario
Questo è un particolare operatore utilizzato per scegliere
quale valore assegnare ad un variabile, basandosi su una
86
certa condizione. Vi propongo un esempio di utilizzo che
ne chiarisce la sintassi:
boolean condizione = true;
int numero = condizione ? 5 : 10;
Traducendo in italiano quello che c’è scritto nella seconda
riga diremo: se la variabile condizione è verificata, allora
assegno alla variabile numero il valore 5, altrimenti
assegno il valore 10.
5.9. Gli array in Java
Tornando all’esempio del controllo doganale, tutti i nostri
pacchi potrebbero essere inseriti in strutture che li
contengono: ad esempio se abbiamo comprato un
bustone di mozzarelle in offerta, ogni mozzarella sarà
contenuta nella sua bustina, ma tutte le mozzarelle
saranno a loro volta contenute nel bustone, sul quale c’è
scritto quante mozzarelle contiene (ed è ovvio che potrà
contenere solo mozzarelle dello stesso tipo).
In Java una struttura come il bustone delle mozzarelle è
l’array; per definire una struttura che contiene numeri
interi, ad esempio, scriveremo:
int[] busta;
87
Se questa busta è il contenitore con i numeri della
tombola, allora possiamo già definire il suo contenuto e
scrivere una dichiarazione completa dell’array:
int[] tombolone = new int[90];
Vediamo ora la sintassi per l’inserimento di elementi in
un array, facendo l’esempio del gioco delle tre carte, dove
solo una è quella vincente; in questo caso, tipico esempio
di utilizzo del valore booleano, potremo dichiarare così
l’array delle tre carte, con una delle tre vincente:
boolean[] treCarte = new boolean[3];
treCarte[0]=false;
treCarte[1]=true;
treCarte[2]=false;
5.10. Istanziare un oggetto: l’utilizzo di “new”
Nella dichiarazione del contenuto abbiamo inserito la
parola chiave new: è una parola che definisce la creazione
di una spazio di memoria nella quale non metteremo un
tipo primitivo, ma un qualsiasi oggetto più complesso, e
questo vale sia per l’array come per la dichiarazione di
un’istanza di un qualsiasi oggetto non primitivo:
Integer base, esponente;
Integer altezza = new Integer(10);
Long larghezza = new Long(20);
Float profondità = new Float(50);
Boolean[] treCarte = new Boolean[3];
treCarte[0]= new Boolean(false);
treCarte[1]= new Boolean(true);
treCarte[2]= new Boolean(false);
88
Più avanti vedremo che, l’utilizzo del new, viene definito
“istruzione” per la creazione di oggetti.
5.11. Una sequenza di caratteri: la classe String
Parlando di array, non si può non fare subito riferimento
all’oggetto String. anche nell’esempio della Moka
abbiamo cominciato a utilizzare il termine stringa,
volendo indicare, con questo termine, una sequenza di
caratteri.
Prendiamo ad esempio una delle istruzioni che abbiamo
usato nell’EsperimentoMoka, ma con un parametro
stavolta diverso:
System.out.println("Ciao");
Nella spiegazione dell’esperimento, abbiamo parlato del
metodo “System.out.println(String s)”, dicendo che accetta
come parametro proprio un oggetto String.
Logicamente possiamo dedurre che l’elemento "Ciao" è
riconducibile ad un oggetto di tipo String; infatti in realtà
si tratta di una sequenza di caratteri che, utilizzando i tipi
primitivi e gli array, potremmo dichiarare come di
seguito:
char[] arrayOfChars = new char[4];
arrayOfChars[0] = 'C';
arrayOfChars[1] = 'i';
arrayOfChars[2] = 'a';
arrayOfChars[3] = 'o';
89
Sarebbe complesso trattare le stringhe come array di
caratteri, e proprio in questo l’oggetto String ci viene in
soccorso: è lui che fa il duro lavoro dietro le quinte di
gestire l’array di caratteri, e a noi programmatori espone
una serie di metodi per una gestione decisamente
facilitata.
Alla fine del capitolo trovate l’EsperimentoMokaString
sull’utilizzo della classe String e di alcuni suoi metodi.
5.12. Matrici e array multidimensionali
Un’importante struttura dati, legata al concetto di array, è
l’array multidimensionale: detta così può sembrare un
oggetto distante anni luce dai nostri problemi quotidiani,
ed invece vi assicuro che, quando vi troverete a tradurre
in Java i vostri problemi, troverete sempre
un’applicazione di questa struttura.
Spiegarla è semplice, perché basta che voi immaginiate la
griglia della battaglia navale (una matrice, come la
chiamerebbero i matematici e gli informatici), non per
forza quadrata: immaginiamo ad esempio un campo di
battaglia con un numero generico di righe e un numero
generico di colonne.
Vediamo la sintassi per dichiarare una matrice così fatta:
int rows = 6, coloumns = 8;
boolean[][] battleField = new boolean[rows][coloumns];
Alla fine del capitolo trovate l’EsperimentoCercaMoka
sull’utilizzo della matrice.
90
5.13. Costruire una frase nel linguaggio Java: le
istruzioni
Come in qualsiasi altra lingua o linguaggio, anche Java ha
le sue frasi: parliamo delle istruzioni.
Analizziamo la classificazione di massima delle istruzioni
Java, sottolineando le tipologie di istruzioni che finora
abbiamo già avuto modo di utilizzare:

Istruzione
o Semplice
 Istruzione vuota
 Costituita solo dal punto e virgola, non
esegue nulla: viene inserita per problemi
di formattazione o chiarezza del codice
 Istruzione di return
 Questa istruzione termina un blocco di
codice, e nel caso dei metodi di un
oggetto, è utilizzata per terminare una
funzione e restituire un risultato
 Istruzione di break
 Questa istruzione è utilizzata per
terminare un’istruzione ripetitiva
 Istruzione di continue
 Questa istruzione è utilizzata per
ricominciare un’istruzione ripetitiva,
senza tener conto di eventuali istruzioni
successive al continue
 Incremento o decremento
91




92
Questa istruzione è utilizzata per
incrementare o decrementare una
variabile di tipo numerico di una unità
o L’istruzione di incremento è
“++”, scritta accanto alla
variabile alla quale sommare
una unità
o L’istruzione di decremento è
“--”, scritta accanto alla
variabile alla quale sommare
una unità
o Se in una istruzione
l’incremento o il decremento è
scritto dopo la variabile, allora
prima viene eseguita
l’istruzione e poi viene
aumentata la variabile; se è
scritto prima, si ottiene il
comportamento contrario
Assegnazione
 L’operatore di assegnazione ‘=’
rappresenta l’istruzione che assegna un
dato valora ad una variabile
Invocazione di un metodo
 L’invocazione del metodo println
dell’oggetto System.out è considerata
un’istruzione
Creazione di un oggetto
 L’utilizzo di “new” rappresenta
un’istruzione di creazione di oggetto
o
Strutturata
 Blocco di codice
 La coppia di parentesi graffe, che
abbiamo già visto all’apertura e
chiusura della classe, e all’apertura e
chiusura di un metodo, rappresenta essa
stessa una singola istruzione che contiene
al suo interno altre istruzioni
 Istruzione condizionale
 Istruzione ripetitiva
5.14. Istruzione condizionale: il costrutto if... else
Il costrutto condizionale if... else da la possibilità allo
sviluppatore di utilizzare blocchi di codice diversi, in base
a condizioni differenti.
Il costrutto è molto semplice da descrivere, e già nella sua
sintassi sta tutta la sua logica di funzionamento:
boolean condizione = ...;
if(condizione){
// Codice eseguito in caso di condizione verificata
}else{
// Codice eseguito in caso di condizione non
// verificata
}
Per tradurla nella nostra lingua madre con questa
istruzione diciamo: “se è vera un data condizione, allora
eseguiamo il blocco di codice successivo, altrimenti
eseguiamo il blocco di codice successivo alla parola
chiave ‘else’”.
93
5.15. Istruzione condizionale: il costrutto switch
Il costrutto condizionale switch da la possibilità allo
sviluppatore di utilizzare blocchi di codice diversi, in base
al valore di una variabile numerica.
Per capirne il significato si può immaginare il
funzionamento di un distributore automatico: in base al
bottone selezionato, che potrebbe essere rappresentato
da un numero, la macchinetta avrà un comportamento
diverso.
Questa la sintassi del costrutto:
int scelta = 2;
switch(scelta){
case 0: macchiato(); break;
case 1: lungo(); break;
case 2: normale(); break;
default: restituisciMoneta();
}
Ad ogni valore possibile della variabile scelta sarà
associato un blocco case: alla fine delle istruzioni
associate ad ognuno dei case, bisognerà inserire
l’istruzione di break, che impedisce all’esecuzione di
andare avanti negli altri casi possibili.
Infine si può inserire un caso default che sarà eseguito
nel caso in cui la variabile scelta non assume nessuno dei
valori elencati nei case.
94
5.16. Istruzione ripetitiva: il costrutto while
Questo costrutto fornisce la possibilità di ripetere lo
stesso blocco di codice fino a che una certa condizione
(variabile di tipo boolean) risulta ancora verificata.
Nel blocco di codice associato al ciclo while si può
usare:


L’istruzione di break, per interrompere il ciclo
e riprendere l’esecuzione a partire dall’istruzione
subito successiva al while, uscendo dal ciclo
L’istruzione continue, per interrompere il ciclo
e riprenderlo dall’inizio.
Qui di seguito la sintassi dell’istruzione while:
boolean condizione = ...;
while(condizione){
// Codice eseguito in caso di condizione verificata
}
95
Ora vi propongo un blocco di codice, che potrete inserire
in un metodo main ed eseguire, per vedere quale sarà il
risultato sulla console, e se è quella che vi aspettate:
public static void main(String[] args) {
int contatore = 0;
while(contatore >= 0){
contatore++;
if(contatore%2==0){
System.out.print(contatore);
}else{
continue;
}
System.out.println(" è un numero pari");
if(contatore==20){
break;
}
}
System.out.println("Il test è finito");
}
5.17. Istruzione ripetitiva: il costrutto for
Il costrutto for è un’istruzione ripetitiva che da la
possibilità di ripetere un blocco di codice per un numero
prestabilito di volte.
Nella dichiarazione di un blocco for, abbiamo la
definizione di un indice, con un suo valora iniziale; poi
dichiariamo una condizione sull’indice e il ciclo verrà
effettuato fino a che questa condizione è vera; infine
definiamo un aggiornamento dell’indice che verrà fatto ad
ogni ciclo completato.
96
Vi propongo un esempio di ciclo for che chiarisce la
sintassi:
char[] arrayOfChars = new char[4];
arrayOfChars[0] = 'C';
arrayOfChars[1] = 'i';
arrayOfChars[2] = 'a';
arrayOfChars[3] = 'o';
int valoreLimite = arrayOfChars.length - 1;
for (int index = 0; index <= valoreLimite; index++) {
System.out.print(arrayOfChars[index]);
}
In questo blocco di codice:





Si definisce un array di caratteri
Vengono associati dei caratteri ad ognuna delle
posizioni dell’array
Poi viene definito un valoreLimite pari alla
lunghezza dell’array creata
Infine abbiamo un istruzione for
o L’indice parte da zero
o Il ciclo sarà ripetuto fino a che l’indice è
inferiore o uguale al valore limite
o Un’istruzione di incremento è
l’aggiornamento che viene fatto alla fine
di ogni ciclo
Nel blocco di codice ripetuto abbiamo la
scrittura sulla console del carattere presente
nell’array nella posizione pari all’indice corrente
97
5.18. EsperimentoMokaString
Ho realizzato, e vi propongo il codice, una riscrittura
della classe EsperimentoMoka alla luce di quello che ci
siamo detti in questo capitolo.
La differenza, come vedrete sta nell’uso dell’oggetto
String, nell’utillizzo degli array, e nell’utilizzo del costrutto
for e degli operatori sulle stringhe.
package esperimento.mokasemplice;
public class EsperimentoMokaString {
/**
* @param args
*/
public static void main(String[] args) {
//Dichiarazione delle stringhe di inizio e fine esperimento
String[] messages = new String[2];
messages[0]=new String("Comincia l’Esperimento Moka");
messages[1]=new String("Fine dell’Esperimento Moka");
//Dichiarazione delle stringhe di descrizione degli steps
String[] steps = new String[5];
steps[0] = new String("Apro la moka");
steps[1] = new String("Metto il caffé");
steps[2] = new String("Chiudo la moka");
steps[3] = new String("Premo sul tasto Avvia");
steps[4] = new String("Il caffé è pronto!");
//Stampa sulla console del messaggio di inizio esperimento
System.out.println(messages[0]);
//Stampa sulla console della descrizione di ogni step
for(int i = 0; i<steps.length; i++){
String index = String.valueOf(i+1);
System.out.println("Passo "+index+": "+steps[i]);
}
//Stampa sulla console del messaggio di fine esperimento
System.out.println(messages[1]);
}
}
98
5.19. EsperimentoCercaMoka
Qui invece vi propongo un semplice esercizio.
Immaginiamo di avere una cucina con una serie di
dispense appese, ed un’altra serie di dispense in basso: in
tutto abbiamo 4 dispense in alto e 4 in basso.
La nostra compagna, ogni volta che lava la Moka dopo
aver fatto il caffè, la posiziona sempre in posti diversi.
Scriviamo un software che posiziona a casa la Moka in
uno qualsiasi di questi scaffali; poi chiede a noi le
coordinate della dispensa dove crediamo che sia la Moka
(‘0,0’ per la prima dispensa in alto a sinistra, fino a ‘2,3’
per l’ultima dispensa in basso a destra), e se la troviamo si
complimenta con noi.
Io ora vi scrivo come ho risolto io il problema, voi
provate a farlo a modo vostro.
package esperimento.mokasemplice;
import java.util.Random;
import java.util.Scanner;
public class EsperimentoCercaMoka {
/**
* EsperimentoCercaMoka
*
* @param args
*/
public static void main(String[] args) {
System.out.println("EsperimentoCercaMoka");
// Instanziazione di un oggetto di tipo Random
// che ha la capacità di creare oggetti con valori
// casuali
Random casuale = new Random();
// Instanziazione della matrice che rappresenta la
// nostra credenza
Boolean[][] credenza = new Boolean[2][4];
99
// Questa variabile diventa verificata (true) quando la
// Moka
// viene posizionata in un posta casuale della credenza
Boolean mokaPosizionata = false;
System.out.println("La tua compagna inizia a scegliere
il posto per la Moka dopo averla lavata");
// Doppio ciclo for:
// 1. Il primo ciclo serve per passare in rassegna tutte
// le righe della matrice
// 2. Il secondo ciclo, per ogni riga, passa in rassegan
// tutte le colonne della matrice
for (int row = 0; row < credenza.length; row++) {
for (int coloumn = 0; coloumn < credenza[0].length;
coloumn++) {
// Prima ci accertiamo che la Moka non sia già stata
// posizionata, perché in questo caso possiamo
// inserire il valore false nelle posizioni restanti
if (!mokaPosizionata) {
// Se la Moka non è posizionata, generiamo un
// prossimo valora casuale booleano per capire se
// è il momento di posizionare la Moka
Boolean posizionareMoka = casuale.nextBoolean();
// Assegniamo il valore ottenuto, sia false che
// true, nella posizione corrente della matrice e
// nel Boolean mokaPosizionata
credenza[row][coloumn] = posizionareMoka;
mokaPosizionata = posizionareMoka;
} else {
credenza[row][coloumn] = false;
}
}
}
// Instanziazione di un oggetto di tipo Scanner che,
// preso come parametro il flusso InputStream dalla
// console, ci fornisce poi una serie di metodi per
// leggere cosa scrive l'utente nella console
Scanner console = new Scanner(System.in);
System.out.println("La tua compagna ha scelto il posto
per la Moka");
System.out.println("Vediamo se ora riesci a trovarla");
// Viene usato il metodo nextInt() dell'oggetto Scanner
// che legge il numero intero che l'utente ha inserito
// nella console e lo assegniamo alla variabile row
100
System.out.print("Inserisci in quale piano della
credenza tu pensi l'abbia messa (0 oppure 1) e premi
invio:");
int row = console.nextInt();
// Viene usato il metodo nextInt() dell'oggetto Scanner
// che legge il numero intero che l'utente ha inserito
// nella console e lo assegniamo alla variabile coloumn
System.out.print("Inserisci in quale sportello della
credenza tu pensi l'abbia messa (0, 1, 2, 3) e premi
invio:");
int coloumn = console.nextInt();
// Chiudiamo il flusso in ingresso dalla console perché
// non ci serve più
console.close();
System.out.println("Tu pensi che la tua compagna
stavolta abbiamo messo la Moka nel piano " + row + " e
nello sportello " + coloumn);
if (credenza[row][coloumn] == true) {
System.out.println("Bravo! Stavolta l'hai
trovata!");
} else {
System.out.println("Mi dispiace... ma anche stavolta
ha vinto la tua compagna!");
}
}
}
101
102
6. Elementi
di
sintassi
per
descrivere il nostro iperuranio
6.1. Le idee nell’iperuranio: sintassi per la
descrizione di una classe
Chi si trova a leggere questo capitolo ha ormai acquisito
tutti gli elementi della grammatica Java per proseguire
nello studio della sintassi: possiamo ora affrontare il
problema della descrizione delle idee del nostro
iperuranio in Java.
Innanzitutto, come avrete già notato negli esempi svolti
nei capitoli precedenti, alla creazione di una classe,
davanti a voi vi si apre un file che inizia con le parole
chiave:
public class NomeClasse{
// Corpo della classe
}
Analizziamo la sintassi partendo dall’esempio:
 public
o Modificatore di accesso: descrive la
visibilità della classe all’interno del
progetto
 public: la classe sarà visibile,
ovvero istanzabile, all’interno di
qualsiasi classe appartenente a
qualsiasi package del progetto
103




class
Parola chiave che dice al compilatore
Java che il prossimo blocco di codice
deve essere interpretato come una classe
NomeClasse
o Il nome della classe deve essere
composto da una sola parola e può
contenere caratteri alfanumerici a meno
di qualche precisazione:
 Non può contenere solo
caratteri numerici
 Non può contenere caratteri
speciali
 Il galateo vorrebbe il nome
cominciasse sempre con la
lettera maiuscola
o Il nome della classe sarà anche il nome
che verrà attribuito al file “.java” che
contiene il codice
o

104
protected: la classe sarà visibile
dalle sue sottoclassi e dalle altre
classi dello stesso package
private: non sarà visibile da
nessun altra classe di nessun
package del progetto
default: se nessuna visibilità è
indicata dallo sviluppatore,
allora il compilatore Java
assegna la visibilità protected

Parentesi graffe
o Segnano il blocco di codice che sarà
interpretato dal compilatore Java come
contenuto di una classe
6.2. Sintassi per la definizione di variabili globali
di una classe
Analizziamo ora la corretta sintassi per dichiarare una
variabile globale all’interno di una classe Java:
public int numero;
protected int base, esponente;
private int altezza = 10;
int larghezza = 20, profondità = 50;
Le regola rispetto alla dichiarazione formale sono le
stesse regole utilizzate per la dichiarazione di variabili
all’interno del corpo di un metodo; la differenza da
sottolineare è la dichiarazione del Modificatore di
accesso per ogni variabile:

Modificatore di accesso: descrive la visibilità
della variabile all’interno del progetto
o public: la variabile sarà visibile dai metodi
della classe di appartenenza e dai metodi
di altre classi che utilizzano un’istanza
della classe corrente
o protected: la variabile sarà visibile dai
metodi della classe di appartenenza e dai
105
o
o
o
metodi di altre classi che estendono la
classe di appartenenza
private: la variabile sarà visibile solo dai
metodi della classe di appartenenza
default: se nessuna visibilità è indicata
dallo sviluppatore, allora il compilatore
Java assegna la visibilità protected
static può essere presente o assente: nel
caso fosse presente significa che la
variabile è strettamente legata alla classe
e non all’istanza della classe. La variabile
può essere raggiunta, quindi, senza
istanziare un oggetto della classe di
appartenenza. Un esempio è la classe
Math che contiene una serie di variabili
statiche che si raggiungono senza la
necessità di istanziare un oggetto Math
double piGreco = Math.PI;
o
106
final può essere presente o assente: nel
caso fosse presente significa che la
variabile non è modificabile in corso di
esecuzione del programma Java
6.3. Sintassi per la definizione dei metodi di una
classe
Analizziamo la sintassi per dichiarare un metodo
all’interno di una classe:
public static void nomeMetodo(Object parametro1, String
paramentro2){
// Corpo del metodo
}
Analizziamo la sintassi partendo dall’esempio:
 public [static]
o Modificatore di accesso: descrive la
visibilità del metodo all’interno del
progetto
 public: il metodo sarà visibile dai
metodi
della
classe
di
appartenenza e dai metodi di
altre classi che utilizzano
un’istanza della classe corrente
 protected: il metodo sarà visibile
dai metodi della classe di
appartenenza e dai metodi di
altre classi che estendono la
classe di appartenenza
 private: il metodo sarà visibile
solo dai metodi della classe di
appartenenza
 default: se nessuna visibilità è
indicata dallo sviluppatore,
107

allora il compilatore Java
assegna la visibilità protected
static può essere presente o
assente: nel caso fosse presente
significa che il metodo è
strettamente legato alla classe e
non all’istanza della classe. Il
metodo può essere invocato,
quindi, senza istanziare un
oggetto
della
classe
di
appartenenza. Un esempio è la
classe Math che contiene una
serie di metodi statici che si
invocano senza la necessità di
istanziare un oggetto Math
double casuale = Math.random();

Integer
Rappresenta il tipo di ritorno del
metodo: in questo caso specifico stiamo
dicendo che il risultato dell’invocazione
di questo metodo è un oggetto Integer.
Se il metodo non ha alcun tipo di
oggetto da restituire si deve utilizzare
void come tipo di ritorno
nomeMetodo
o Il nome del metodo deve essere
composto da una sola parola e può
contenere caratteri alfanumerici a meno
di qualche precisazione:
o

108
Non può contenere solo
caratteri numerici
 Non può contenere caratteri
speciali
 Il galateo vorrebbe il nome di
un metodo cominciasse sempre
con la lettera minuscola
(String parametro1, String parametro2)
o Tra parentesi tonde viene inserita la lista
dei parametri necessari all’esecuzione del
metodo; ogni parametro viene indicato
con Tipo e nome e diviso da una virgola
dagli altri parametri


Ora vi propongo il codice di una semplice classe di
esempio nella quale potrete verificare tutti i modi di
invocazione di un metodo:
package esperimento.numeronaturale;
public class NumeroNaturale {
private int numero;
public static double media(int a, int b){
return (double) ((a+b)/2);
}
public double doppio(){
return numero*2;
}
public void dimezza(){
numero/=2;
}
109
/**
* @param args
*/
public static void main(String[] args) {
int n1=5,n2=15;
double media = NumeroNaturale.media(n1, n2);
System.out.println("La media tra "+n1+" e "+n2+" é
"+media);
NumeroNaturale nn = new NumeroNaturale();
nn.numero = 10;
System.out.println("Il NumeroNaturale è "+nn.numero);
double nDoppio = nn.doppio();
System.out.println("Il doppio del NumeroNaturale è
"+nDoppio);
System.out.println("Dimezzo il NumeroNaturale");
nn.dimezza();
System.out.println("Il NumeroNaturale è "+nn.numero);
}
}
6.4. Metodo costruttore
Il metodo costruttore è utilizzato, come suggerisce il suo
stesso nome, alla creazione dell’istanza di un oggetto.
Questo metodo si presenta con una sintassi simile a
quella dei metodi normali; la sua particolarità è legata al
fatto che il nome del metodo è identico al nome della
classe e non avrà nessun tipo di ritorno indicato.
Ecco un esempio di costruttore:
public NumeroNaturale(int numeroNaturale){
this.numero = numeroNaturale;
}
In questo metodo ci occuperemo di tutta la preparazione
necessaria alla creazione di un’istanza di un oggetto,
110
partendo da una serie di parametri; è molto importante
sapere che ogni classe può avere diversi costruttori che
differiscono per i parametri in ingresso.
6.5. Ereditarietà delle classi
Abbiamo già parlato del concetto di Polimorfismo e
Ereditarietà tra le classi, ora ci occuperemo del come
descrivere utilizzando il linguaggio Java, il fatto che una
classe estenda un’altra classe.
La sintassi è molto semplice; per dire che la classe Giallo
estende la classe Libro scriveremo:
public class Giallo extends Libro{
// Corpo della classe
}
All’interno della classe Giallo potremo quindi utilizzare
tutti i metodi e le variabili visibili della classe Libro, come
se fossero istanziate nella stessa classe.
In più potremo sovrascrivere l’implementazione di un
metodo, cambiandone il comportamento, qualora fosse
necessario, sfruttando una possibilità dell’overriding:
basta aggiungere l’annotation “@Override” prima del
metodo, per comunicare al compilatore che siamo
davanti ad un metodo già presente nella classe madre,
ovvero la cosiddetta superclasse.
111
6.6. Esperimento Libreria: specifiche
L’obiettivo di questo esperimento riguardo l’ereditarietà
sarà quello di creare un oggetto “Libro”, con una serie di
variabili ed un metodo specifico, ed un oggetto “Giallo”
che lo estende e che fa overriding del metodo
implementato nella superclasse.
Mettetevi al lavoro con il vostro IDE:
 Create un nuovo progetto, come visto nei
capitoli
precedenti,
e
chiamatelo
“EsperimentoLibreria” (figura 39)
 Create il package “esperimento.libreria”
(figura 40)
 Create la classe “Libro” senza un metodo main
(figura 41)
A questo punto possiamo descrivere la nostra idea di
“Libro” definendo le variabili della classe come di
seguito:
package esperimento.libreria;
public class Libro {
public String titolo, autore;
public double prezzo;
}
Dopodiché, per ogni variabile, aggiungeremo una coppia
di metodi che hanno il compito di restituire il valore della
112
variabile e di cambiarlo, i cosiddetti metodi “getter and
setter”.
Per farlo il nostro IDE ci viene in soccorso:
 Cliccate con il tasto destro su una qualsiasi delle
variabili
 Selezionate la voce “Source → Generate Getters
and Setters...” (figura 42)
 Nella finestra di dialogo che si aprirà potrete
scegliere per quali variabili generare i metodi (e
noi le sceglieremo tutte) e in più l’Insertion Point,
ovvero il punto in cui verrà inserito il codice
generato (e noi sceglieremo Last member, ovvero
sempre alla fine della classe)
 Si possono anche scegliere la visibilità (per noi
sarà public)
 Si può chiedere di generare i commenti ai metodi
(ed è sempre corretto ed elegante farlo)
spuntando la checkbox con l’etichetta “Generate
method comments”
 Cliccate su OK (figura 43) e avrete tutti i metodi
automaticamente generati (figura 44)
Aggiungiamo ora noi un metodo costruttore ed un
metodo che ci restituisce una descrizione del libro:
package esperimento.libreria;
public class Libro {
public String titolo, autore;
public double prezzo;
/**
* Costruttore
* @param titolo Titolo del libro
113
* @param autore Autore del libro
* @param prezzo Prezzo in Euro del libro
*/
public Libro(String titolo, String autore, double prezzo){
setTitolo(titolo);
setAutore(autore);
setPrezzo(prezzo);
}
/**
* Metodo che restituisce una descrizione del libro
* @return String contenente la descrizione del libro
*/
public String descrizione(){
return "Libro: "+titolo+" di "+autore+" - Costo di
copertina: €"+prezzo;
}
/**
* @return the titolo
*/
public String getTitolo() {
return titolo;
}
/**
* @param titolo the titolo to set
*/
public void setTitolo(String titolo) {
this.titolo = titolo;
}
/**
* @return the autore
*/
public String getAutore() {
return autore;
}
/**
* @param autore the autore to set
*/
public void setAutore(String autore) {
this.autore = autore;
}
/**
114
* @return the prezzo
*/
public double getPrezzo() {
return prezzo;
}
/**
* @param prezzo the prezzo to set
*/
public void setPrezzo(double prezzo) {
this.prezzo = prezzo;
}
}
Il nostro oggetto “Libro” è pronto per l’uso.
Ora è il momento di creare la sua estensione “Giallo”:
 Nello stesso package dell’oggetto “Libro”, create
una nuova classe
 Nella finestra di dialogo di creazione della classe,
inserite il nome “Giallo” e stavolta sfruttate
anche il campo “Superclass”; cliccate sul tasto
“Browse”, posto accanto al campo che contiene
il nome della superclasse della quale il nostro
nuovo oggetto sarà estensione (figura 45)
 La finestra di dialogo che vi si apre davanti è una
finestra nella quale potrete cercare e scegliere la
superclasse che volete estendere (figura 46). Nel
campo “Choose a type” scrivete il nome della
superclasse “Libro” e l’IDE vi mostrerà i risultati
che corrispondono al nome che state cercando
(figura 47)
 Selezionate il risultato che vi interessa (Libro esperimento.libreria) e cliccate su OK
115


Spuntate la voce “Constructors from superclass”:
l’IDE scriverà per noi il costruttore della classe
che eredita, sfruttando il costruttore della
superclasse e utilizzando la corretta sintassi
Finiti tutti i settaggi (figura 48) cliccate su OK
Aggiungiamo ora le variabili specifiche all’oggetto
“Giallo” e i metodi “getters and setters”:
package esperimento.libreria;
public class Giallo extends Libro {
public String colpevole;
/**
* Costruttore senza colpevole
* @param titolo Titolo del libro
* @param autore Autore del libro
* @param prezzo Prezzo in Euro del libro
*/
public Giallo(String titolo, String autore, double prezzo) {
super(titolo, autore, prezzo);
}
/**
* Costruttore con il colpevole
* @param titolo Titolo del libro
* @param autore Autore del libro
* @param prezzo Prezzo in Euro del libro
* @param colpevole Nome del personaggio colpevole del
delitto nel giallo
*/
public Giallo(String titolo, String autore, double prezzo,
String colpevole) {
super(titolo, autore, prezzo);
setColpevole(colpevole);
}
/**
* @return the colpevole
*/
116
public String getColpevole() {
return colpevole;
}
/**
* @param colpevole the colpevole to set
*/
public void setColpevole(String colpevole) {
this.colpevole = colpevole;
}
}
A questo punto possiamo decidere di implementare una
versione particolare del metodo che restituisce la
descrizione del libro, sfruttando il polimorfismo e
l’annotazione “@Override”:
package esperimento.libreria;
public class Giallo extends Libro {
public String colpevole;
/**
* Metodo che restituisce una descrizione del libro giallo
* @return String contenente la descrizione del libro giallo
*/
@Override
public String descrizione(){
return "Libro Giallo: "+titolo+" di "+autore+" - Costo
di copertina: €"+prezzo+" - Nome del personaggio colpevole:
"+colpevole;
}
/**
* Costruttore senza colpevole
* @param titolo Titolo del libro
* @param autore Autore del libro
* @param prezzo Prezzo in Euro del libro
*/
public Giallo(String titolo, String autore, double prezzo) {
super(titolo, autore, prezzo);
}
/**
117
* Costruttore con il colpevole
* @param titolo Titolo del libro
* @param autore Autore del libro
* @param prezzo Prezzo in Euro del libro
* @param colpevole Nome del personaggio colpevole del
delitto nel giallo
*/
public Giallo(String titolo, String autore, double prezzo,
String colpevole) {
super(titolo, autore, prezzo);
setColpevole(colpevole);
}
/**
* @return the colpevole
*/
public String getColpevole() {
return colpevole;
}
/**
* @param colpevole the colpevole to set
*/
public void setColpevole(String colpevole) {
this.colpevole = colpevole;
}
}
Ed
ora
possiamo
creare
una
classe
“EsperimentoLibreria”, con un metodo main nel quale:
 Istanziamo un oggetto Libro
 Istanziamo un oggetto Giallo
 Stampiamo sulla console le loro due descrizioni
118
Ecco il codice della classe:
package esperimento.libreria;
public class EsperimentoLibreria {
/**
* @param args
*/
public static void main(String[] args) {
Libro wilde = new Libro("The Picture of Dorian Gray",
"Oscar Wilde", new Double(18.50));
Libro christie = new Giallo("Murder in Mesopotamia",
"Agatha Christie", new Double(15.50),"Il professor Leidner");
System.out.println(wilde.descrizione());
System.out.println(christie.descrizione());
}
}
Eseguite la classe e vedrete nella console il risultato nel
quale la descrizione dei due oggetti “Libro” sarà diversa
grazie all’override del metodo che abbiamo implementato
nella classe “Giallo” (figura 49).
119
Figura 39
120
Figura 40
121
Figura 41
122
Figura 42
123
Figura 43
124
Figura 44
125
Figura 45
126
Figura 46
127
128
Figura 47
Figura 48
129
Figura 49
130
6.7. Classe astratta
In Java si ha la possibilità di definire delle classi che, per
loro natura, devono necessariamente essere estese.
Un tipico esempio che tutti gli informatici hanno visto
nella loro vita è quello della Figura Geometrica: in pratica
noi possiamo definire l’idea di Figura Geometrica,
sapendo che certamente avrà un perimetro ed un area, ma
saranno le varie estensioni particolari di Figura
Geometrica (Quadrato, Rettangolo, Triangolo, ...) che
potranno implementare la logica di calcolo del perimetro
e dell’area.
Queste classi vengono dette astratte: avranno una lista di
metodi, detti a loro volta astratti, che dovranno
necessariamente trovare implementazione nelle classi che
estenderanno la classe astratta in cui sono definiti.
Vi propongo un esempio che chiarisce la sintassi e
l’utilizzo della parola chiave abstract:
package esperimento.figurageometrica;
public abstract class FiguraGeometrica {
public abstract double perimetro();
public abstract double area();
public String descrizione(){
return "Questa FiguraGeometrica ha un perimetro di
"+perimetro()+" e un'area di "+area();
}
}
131
package esperimento.figurageometrica;
public class Quadrato extends FiguraGeometrica {
private double lato;
@Override
public double perimetro() {
return getLato()*4;
}
@Override
public double area() {
return getLato()*getLato();
}
/**
* @return the lato
*/
public double getLato() {
return lato;
}
/**
* @param lato the lato to set
*/
public void setLato(double lato) {
this.lato = lato;
}
}
6.8. Interfacce
Nel linguaggio Java si definisce interfaccia la definizione
di una lista di metodi, senza implementazione, che
definisce una sorta di codice di comportamento di un
oggetto: se una classe implementa un’interfaccia, allora
si impegna a fornire un’implementazione di tutti i metodi
contenuti nell’interfaccia.
132
Per creare un’interfaccia basta cliccare il tasto destro su
un package e scegliere la voce New → Intrerface (figura
50).
Nella finestra di dialogo si può inserire il nome
dell’interfaccia e premere su OK.
A questo punto avrete davanti a voi un blocco di codice
in cui inserire:
 una lista di metodi, senza specificarne la loro
implementazione;
 costanti (ovvero variabili globali static final)
Vi fornisco un esempio che chiarisce la sintassi e
l’utilizzo:
package esperimento.figurageometrica;
public interface Triangolo {
static final double coeffSemiPerimetro = 0.5;
public double calcolaSemiperimetro();
public double calcolaAreaByErone();
}
package esperimento.figurageometrica;
public abstract class FiguraGeometrica {
/**
* Perimetro della Figura Geometrica
* @return perimetro della figura
*/
public abstract double perimetro();
/**
* Area della Figura Geometrica
* @return area della figura
*/
public abstract double area();
/**
* Descrizione della Figura
* @return descrizione dettagliata della figura geometrica
133
*/
public String descrizione(){
return "Questa FiguraGeometrica ha un perimetro di
"+perimetro()+" e un'area di "+area();
}
/**
* Metodo toString proprio dell'oggetto {@link
FiguraGeometrica}
*/
@Override
public String toString(){
return descrizione();
}
}
package esperimento.figurageometrica;
public class Quadrato extends FiguraGeometrica {
/**
* Lato del quadrato
*/
private double lato;
/**
* Costruttore del quadrato
* @param lato LMato del quadrato
*/
public Quadrato(double lato){
setLato(lato);
}
@Override
public double perimetro() {
return getLato()*4;
}
@Override
public double area() {
return getLato()*getLato();
}
/**
* @return the lato
*/
public double getLato() {
return lato;
134
}
/**
* @param lato the lato to set
*/
public void setLato(double lato) {
this.lato = lato;
}
}
package esperimento.figurageometrica;
public class TriangoloScaleno extends FiguraGeometrica
implements Triangolo {
/**
* Lati del triangolo
*/
private double a,b,c;
/**
* Costruttore di default
*/
public TriangoloScaleno() {
setA(10);
setB(10);
setC(10);
}
/**
* Costruttore
* @param a lato del triangolo
* @param b lato del triangolo
* @param c lato del triangolo
*/
public TriangoloScaleno(double a, double b, double c) {
setA(a);
setB(b);
setC(c);
}
@Override
public double perimetro() {
return getA()+getB()+getC();
}
135
@Override
public double area() {
return calcolaAreaByErone();
}
/**
* @return the a
*/
public double getA() {
return a;
}
/**
* @param a the a to set
*/
public void setA(double a) {
this.a = a;
}
/**
* @return the b
*/
public double getB() {
return b;
}
/**
* @param b the b to set
*/
public void setB(double b) {
this.b = b;
}
/**
* @return the c
*/
public double getC() {
return c;
}
/**
* @param c the c to set
*/
public void setC(double c) {
this.c = c;
}
136
/**
* Metodo dell'interfaccia implementata
*/
@Override
public double calcolaSemiperimetro() {
return Triangolo.coeffSemiPerimetro*(perimetro());
}
/**
* Metodo dell'interfaccia implementata
*/
@Override
public double calcolaAreaByErone() {
return
Math.sqrt(calcolaSemiperimetro()*(calcolaSemiperimetro()getA())*(calcolaSemiperimetro()-getB())*(calcolaSemiperimetro()getC()));
}
}
package esperimento.figurageometrica;
public class TriangoloRettangolo extends FiguraGeometrica
implements Triangolo {
/**
* Lati del triangolo rettangolo
*/
private double cateto1,cateto2,ipotenusa;
public TriangoloRettangolo() {
setCateto1(3);
setCateto2(4);
setIpotenusa(Math.sqrt(Math.pow(cateto1,2)+Math.pow(cate
to2,2)));
}
@Override
public double perimetro() {
return getCateto1()+getCateto2()+getIpotenusa();
}
@Override
public double area() {
return getCateto1()*getCateto2()/2;
}
137
/**
* @return the cateto1
*/
public double getCateto1() {
return cateto1;
}
/**
* @param cateto1 the cateto1 to set
*/
public void setCateto1(double cateto1) {
this.cateto1 = cateto1;
}
/**
* @return the cateto2
*/
public double getCateto2() {
return cateto2;
}
/**
* @param cateto2 the cateto2 to set
*/
public void setCateto2(double cateto2) {
this.cateto2 = cateto2;
}
/**
* @return the ipotenusa
*/
public double getIpotenusa() {
return ipotenusa;
}
/**
* @param ipotenusa the ipotenusa to set
*/
public void setIpotenusa(double ipotenusa) {
this.ipotenusa = ipotenusa;
}
138
/**
* Metodo dell'interfaccia implementata
*/
@Override
public double calcolaSemiperimetro() {
return Triangolo.coeffSemiPerimetro*(perimetro());
}
/**
* Metodo dell'interfaccia implementata
*/
@Override
public double calcolaAreaByErone() {
return
Math.sqrt(calcolaSemiperimetro()*(calcolaSemiperimetro()getCateto1())*(calcolaSemiperimetro()getCateto2())*(calcolaSemiperimetro()-getIpotenusa()));
}
}
package esperimento.figurageometrica;
public class EsperimentoFiguraGeometrica {
public static void main(String[]args) {
FiguraGeometrica[] figure = new FiguraGeometrica[3];
figure[0] = new Quadrato(10);
figure[1] = new TriangoloScaleno();
figure[2] = new TriangoloRettangolo();
for(int i=0; i<figure.length; i++){
System.out.println(figure[i]);
}
}
}
139
140
Figura 50
6.9. La classe Object
Non si può concludere un capitolo legato alle classi e agli
oggetti Java senza aver parlato della classe Object.
Questa classe, volendo rimanere nell’ambito del
parallelismo tra programmazione orientata agli oggetti e
Iperuranio Platonico, potremmo dire che rappresenta
“l’idea delle idee”: in pratica tutte le idee sono istanze di
questa idea.
Tutti gli oggetti Java sono implicite estensioni della classe
Object; e cosa ereditano da questa classe? Innanzitutto
ereditano un codice di comportamento che ogni oggetto
Java dovrà seguire, del quale ci tengo subito a elencarne
due punti fondamentali che già chi si affaccia alla
programmazione Java può comprendere e seguire:
 Ogni oggetto dovrà essere capace di confrontarsi
con un altro oggetto dello stesso tipo e dire se è
uguale o meno
o A questo scopo eredita il metodo
equals, del quale ovviamente potrà fare
overriding e implementarne uno
specifico
 Ogni oggetto dovrà essere capace di convertirsi
in una stringa, ovvero di fornire una
rappresentazione in String dell’oggetto; potrà poi
ad esempio essere passato come parametro al
metodo System.out.println(obj)
o A questo scopo eredita il metodo
toString, del quale ovviamente potrà
fare overriding e implementarne uno
specifico
141
6.10. Come implementare
metodo equals
correttamente
il
In questo piccolo volume dedicato al linguaggio Java, mi
è capitato di fare riferimento al galateo, perché ci tengo a
precisare che ci sono delle buone abitudini che gli
sviluppatori dovrebbero sempre tener presenti per
scrivere del codice di buon livello: una di queste buone
abitudini è strettamente legata all’implementazione del
metodo equals.
Consiglio a tutti gli sviluppatori che si trovano davanti
alla necessità di implementare il metodo equals per una
loro classe, di implementare anche il metodo hashcode: è
un metodo che restituisce una traduzione in hash (una
traduzione
che
potremmo
definire
numerica,
semplificandone il senso) del proprio oggetto.
Ci sono molti costrutti in Java, ad esempio, che, per
determinare l’uguaglianza tra oggetti, sfruttano proprio il
loro hashcode e non il metodo equals: per evitare che il
vostro oggetto possa avere comportamenti non voluti in
situazioni inaspettate, pensate alle buone abitudini
quando siete in tempo per farlo.
Cominciamo con il dire che l’implementazione dei
metodi equals e hashcode deve rispettare alcune
restrizioni importanti; la relazione deve essere:
 Simmetrica:
se objA.equals(objB) allora
b.equals(objA);
 Riflessiva: per qualsiasi oggetto diverso da null,
objA.equals(objA) deve essere verificata;
 Transitiva
:
se
objA.equals(objB)
e
objB.equals(objC) allora objA.equals(objC)
142
Inoltre i metodi hashCode() e equals devono essere
consistenti, ovvero, due oggetti uguali per il metodo
equals devono necessariamente avere lo stesso hashcode,
mentre la relazione inversa non è necessaria.
Nella classe Object, il metodo equals ha la seguente
implementazione:
public boolean equals(Object obj) {
return (this == obj);
}
Il metodo verifica, attraverso l’operatore “==” che
l’oggetto corrente, ovvero il this, sia uguale all’oggetto
passato come parametro: nel caso di tipi primitivi non ci
sarebbero problemi, ma nel caso di oggetti complessi in
questo caso non verifichiamo il contenuto dell’oggetto,
ma la sola referenza in memoria.
Praticamente il metodo equals, per default, verifica che
l’oggetto passato come parametro sia proprio lo stesso
oggetto corrente (this): noi invece dobbiamo ridefinire il
metodo equals per riconoscere che due oggetti distinti,
due istanze dello stesso oggetto, abbiano caratteristiche
tali da poter essere definiti identici.
Il metodo hashcode, invece, nell’implementazione di
default nella classe Object, restituisce l’indirizzo in
memoria convertito in numero intero.
143
Ecco un esempio di implementazione dei metodi equals e
hashcode:
package esperimento.figurageometrica;
public class TriangoloScaleno extends FiguraGeometrica
implements Triangolo {
/**
* Lati del triangolo
*/
private double a,b,c;
/**
* Costruttore di default
*/
public TriangoloScaleno() {
setA(10);
setB(10);
setC(10);
}
/**
* Costruttore
* @param a lato del triangolo
* @param b lato del triangolo
* @param c lato del triangolo
*/
public TriangoloScaleno(double a, double b, double c) {
setA(a);
setB(b);
setC(c);
}
@Override
public double perimetro() {
return getA()+getB()+getC();
}
@Override
public double area() {
return calcolaAreaByErone();
}
144
/**
* @return the a
*/
public double getA() {
return a;
}
/**
* @param a the a to set
*/
public void setA(double a) {
this.a = a;
}
/**
* @return the b
*/
public double getB() {
return b;
}
/**
* @param b the b to set
*/
public void setB(double b) {
this.b = b;
}
/**
* @return the c
*/
public double getC() {
return c;
}
/**
* @param c the c to set
*/
public void setC(double c) {
this.c = c;
}
/**
* Metodo dell'interfaccia implementata
*/
@Override
public double calcolaSemiperimetro() {
145
return Triangolo.coeffSemiPerimetro*(perimetro());
}
/**
* Metodo dell'interfaccia implementata
*/
@Override
public double calcolaAreaByErone() {
return
Math.sqrt(calcolaSemiperimetro()*(calcolaSemiperimetro()getA())*(calcolaSemiperimetro()-getB())*(calcolaSemiperimetro()getC()));
}
@Override
public boolean equals(Object obj) {
if(obj instanceof TriangoloScaleno){
TriangoloScaleno ts = (TriangoloScaleno) obj;
return getA()==ts.getA()
&& getB()==ts.getB()
&& getC()==ts.getC();
}else{
return false;
}
}
@Override
public int hashCode() {
int hash = 1;
hash = hash * 17 + (int) Math.round(getA());
hash = hash * 31 + (int) Math.round(getB());
hash = hash * 13 + (int) Math.round(getC());
return hash;
}
}
146
7. Impariamo a gestire i nostri
errori
7.1. Exception: l’idea dell’errore in Java
Una delle cose più complesse e necessarie nella
concezione di un componente software, per quanto
semplice possiate immaginarlo, è la gestione degli errori;
quando vi trovate davanti ad un problema da affrontare e
risolvere attraverso la scrittura di una procedura software
di qualsiasi natura, dovrete sempre immaginare e
progettare la soluzione al problema, ma specificando e
gestendo tutte le possibili anomalie di comportamento
della vostra soluzione.
Per affrontare al meglio vi consiglio di ragionare come un
ingegnere
dell’Automazione
Industriale,
ovvero,
immaginando sempre un problema come una serie di
variabili di ingresso, una dinamica di funzionamento del
processo, e delle variabili in uscita: ognuna di queste
componenti ha un dominio di validità, oltre i limiti del
quale il processo non può essere lanciato o, qualora
lanciato, non può essere correttamente portato a termine.
7.2. Esperimento della divisione fra numeri
decimali: specifiche
Un esempio semplice, ma efficace da un punto di vista
della comprensione del problema, è la realizzazione di un
147
metodo che realizza la divisione tra numeri decimali;
verifichiamo le condizioni iniziali:
 Le variabili in ingresso devono contenere un
valore (questo significa che devono essere
diverse dal valore null)
 Il denominatore deve necessariamente essere
diverso dal valore zero, per ottenere un risultato
diverso dall’infinito
Nell’esperimento realizziamo:
 Un progetto dal nome EsperimentoDivisione
 Un package esperimento.divisione
 Una classe EsperimentoDivisione.java
o Un metodo pubblico e statico dividi che
prende in ingresso due variabili di tipo
Double e ne restituisce una terza che è il
risultato della divisione tra i due numeri
in ingresso
o Un metodo main che inizializza due
variabili random di tipo Double e
stampa sulla console una String del tipo
“Il risultato della divisione tra 6 e 3 è 2”
7.3. Esperimento della divisione fra numeri
decimali: considerazioni sulle eccezioni
Leggendo le specifiche di un progetto, spesso non
troverete riferimenti ai possibili casi di errore: è abilità
dello sviluppatore e di chi si occupa del testing del
148
software quella di prevedere le possibili anomalie di
funzionamento.
Cominciamo anche con il precisare che il galateo nel
linguaggio Java consiglia di verificare all’inizio di ogni
metodo queste condizioni di funzionamento al fine di
evitare il lancio di un metodo che genererebbe una
Exception durante la propria esecuzione; nel nostro IDE
Eclipse è facile verificarne il risultato, scrivendo una
classe con un metodo main ed un metodo che realizza la
divisione fra numeri decimali, ma senza la giusta gestione
dell’errore:
package esperimento.divisione;
public class EsperimentoDivisione {
/**
* @param args
*/
public static void main(String[] args) {
eseguiDivisione();
}
/**
* Metodo eseguiDivisione
*/
public static void eseguiDivisione() {
Double a = Math.random();
Double b = null;
Double risultato = dividi(a, b);
System.out.println("Il risultato della divisione tra
"+a+" e "+b+" è "+risultato);
}
/**
* Metodo che realizza la divisione tra numeri decimali
* @param numeratore variabile di tipo Double
* @param denominatore variabile di tipo Double
* @return risultato della divisione
149
*/
public static Double dividi(Double numeratore, Double
denominatore){
return numeratore/denominatore;
}
}
Come vedete dal codice il denominatore l’abbiamo
inizializzato a null; se eseguite il main vedrete che
l’esecuzione viane bruscamente bloccata dal lancio di una
Exception:
Exception in thread "main" java.lang.NullPointerException
at esperimento.divisione.EsperimentoDivisione.dividi
(EsperimentoDivisione.java:31)
at esperimento.divisione.EsperimentoDivisione.eseguiDivisione
(EsperimentoDivisione.java:19)
at esperimento.divisione.EsperimentoDivisione.main
(EsperimentoDivisione.java:9)
Evidentemente in fase di compilazione nessuno ha
potuto segnalare un’anomalia, perché da un punto di vista
strettamente teorico non c’era niente di sbagliato nel
metodo che abbiamo scritto per realizzare la divisione;
ma al momento dell’esecuzione, la macchina virtuale si è
trovata davanti ad una situazione che non sa gestire,
quindi ha lanciato un errore che ha fermato il
funzionamento.
Uno dei compiti principali di uno sviluppatore è quella di
prevedere il più possibile questi errori, gestendoli o
semplicemente bloccando l’esecuzione di un metodo
spiegandone il motivo.
Nel caso specifico possiamo decidere di gestire
l’eccezione restituendo a nostra volta un risultato null per
la divisione, ma evitando l’arresto brusco dell’esecuzione:
150
/**
* Metodo che realizza la divisione tra numeri decimali
* @param numeratore variabile di tipo Double
* @param denominatore variabile di tipo Double
* @return risultato della divisione, null se denominatore e/o
numeratore sono null
*/
public static Double dividi(Double numeratore, Double
denominatore){
if(numeratore == null || denominatore == null){
return null;
}
return numeratore/denominatore;
}
Stavolta non avremo un arresto inaspettato e il risultato
sarà una stringa del tipo “Il risultato della divisione tra
0.3370904229000804 e null è null”.
7.4. La classe Exception
Come si è potuto vedere nel risultato dell’esperimento
precedente, l’errore è stato segnalato attraverso la dicitura
in
Console
“Exception
in
thread
"main"
java.lang.NullPointerException”, con poi le indicazioni del
numero di riga nel quale è avvenuta l’anomalia.
La classe “java.lang.NullPointerException” è un’estensione
della classe Exception; quest’ultima rappresenta l’oggetto
interpretato dalla Java Virtual Machine come una generica
anomalia di funzionamento: tutti gli errori più specifici,
per essere interpretati come eccezioni, dovranno essere
oggetti che estendono la classe Exception e inoltre,
151
sempre facendo riferimento al galateo, dovranno avere un
nome che finisce sempre con la parola Exception.
Nel caso specifico la classe NullPointerException è
un’estensione della classe Exception che segnala la
presenza inaspettata di una variabile con valore null.
7.5. Elementi di sintassi: le parole chiave
“throws” e “throw”
Ogni metodo può al suo interno lanciare una nuova
Exception attraverso l’uso della parola chiave throw; può
altresì specificare tutte le Exceptions che sono
potenzialmente lanciate all’interno del suo blocco di
codice attraverso l’utilizzo della parola chiave throws;
mostriamo un esempio che chiarisce la sintassi:
/**
* Metodo che realizza la divisione tra numeri decimali
* @param numeratore variabile di tipo Double
* @param denominatore variabile di tipo Double
* @return risultato della divisione
*/
public static Double dividi(Double numeratore, Double
denominatore)
throws NullPointerException, IllegalArgumentException{
if(denominatore == 0){
throw new IllegalArgumentException();
}
return numeratore/denominatore;
}
152
7.6. Elementi di sintassi: blocco try... catch...
finally
All’interno del blocco di codice di un metodo nel quale
utilizziamo un metodo che segnala le sue potenziali
eccezioni con un throws, abbiamo due possibilità:
 Evitare di gestire le eccezioni e rilanciare a nostra
volta le Exceptions aggiungendole nell’elenco del
throws del nostro metodo
 Gestire l’eccezione posizionando l’invocazione
del metodo che potenzialmente lancia
un’eccezione all’interno di un blocco try
o Alla fine di un blocco try, dobbiamo
inserire una serie di blocchi catch, uno
per ogni Exception potenzialmente
lanciata, con dentro il codice eseguito
nel caso si dovesse verificare l’errore
specifico
o Dopo i blocchi catch si può inserire un
blocco finally nel quale si specifica un
blocco di codice di codice eseguito in
ogni caso dopo il blocco try, sia quindi
nel caso in cui si siano verificate
eccezioni, sia nel caso contrario.
153
Vediamo una classe di esempio che ne mostra la sintassi e
l’utilizzo:
/**
* Metodo eseguiDivisione con gestione delle eccezioni
*/
public static void eseguiDivisione() {
Double a = Math.random();
Double b = null;
Double risultato = null;
try{
risultato = dividi(a, b);
}catch(IllegalArgumentException e){
System.out.println(e);
}finally{
System.out.println("Il risultato della divisione tra
"+a+" e "+b+" è "+risultato);
}
}
/**
* Metodo che realizza la divisione tra numeri decimali
* @param numeratore variabile di tipo Double
* @param denominatore variabile di tipo Double
* @return risultato della divisione
* @throws IllegalArgumentException
*/
public static Double dividi(Double numeratore, Double
denominatore) throws IllegalArgumentException{
if(numeratore == null || denominatore == null){
throw new IllegalArgumentException("Numeratore e/o
denominatore nullo");
}else if(denominatore == 0){
throw new IllegalArgumentException("Denominatore uguale
a zero");
}
return numeratore/denominatore;
}
154
7.7. Creazione di errore specifici
Uno sviluppatore puo creare dfelle proprie specifriche
Excpetion soltanto creando delle normali classi Java che
estendono la classe Exception e che implementano tutti i
costruttori ereditati dalla classe Exception.
Ecco un esempio di Exception personalizzata:
package esperimento.divisione;
public class DivisioneException extends Exception {
/**
* Costruttore della classe {@link DivisioneException}
*/
public DivisioneException(Double numeratore, Double
denominatore) {
super("numeratore: "+numeratore+" denominatore:
"+denominatore);
}
/**
* Costruttore della classe {@link DivisioneException}
* @param arg0
*/
public DivisioneException(Double numeratore, Double
denominatore, String arg0) {
super("numeratore: "+numeratore+" denominatore:
"+denominatore+" -> "+arg0);
}
/**
* Costruttore della classe {@link DivisioneException}
* @param arg0
*/
public DivisioneException(Double numeratore, Double
denominatore, Throwable arg0) {
super("numeratore: "+numeratore+" denominatore:
"+denominatore+" -> "+arg0);
}
/**
* Costruttore della classe {@link DivisioneException}
155
* @param arg0
* @param arg1
*/
public DivisioneException(Double numeratore, Double
denominatore, String arg0, Throwable arg1) {
super("numeratore: "+numeratore+" denominatore:
"+denominatore+" -> "+arg0, arg1);
}
/**
* Costruttore della classe {@link DivisioneException}
* @param arg0
* @param arg1
* @param arg2
* @param arg3
*/
public DivisioneException(Double numeratore, Double
denominatore, String arg0, Throwable arg1, boolean arg2,
boolean arg3) {
super("numeratore: "+numeratore+" denominatore:
"+denominatore+" -> "+arg0, arg1, arg2, arg3);
}
}
package esperimento.divisione;
public class EsperimentoDivisione {
/**
* @param args
*/
public static void main(String[] args) {
eseguiDivisione();
}
/**
* Metodo eseguiDivisione
*/
public static void eseguiDivisione() {
Double a = Math.random();
Double b = null;
Double risultato = null;
try{
risultato = dividi(a, b);
}catch(DivisioneException e){
System.out.println(e);
156
}finally{
System.out.println("Il risultato della divisione tra
"+a+" e "+b+" è "+risultato);
}
}
/**
* Metodo che realizza la divisione tra numeri decimali
* @param numeratore variabile di tipo Double
* @param denominatore variabile di tipo Double
* @return risultato della divisione
* @throws DivisioneException
*/
public static Double dividi(Double numeratore, Double
denominatore) throws DivisioneException{
if(numeratore == null || denominatore == null){
throw new DivisioneException(numeratore,
denominatore, "Numeratore e/o denominatore nullo");
}else if(denominatore == 0){
throw new DivisioneException(numeratore,
denominatore, "Denominatore uguale a zero");
}
return numeratore/denominatore;
}
}
157
158
8. Conclusioni
8.1. Ora è il momento di approfondire
Ho scritto questo libro pensando di realizzare non un
manuale, ma una sorta di “racconto tecnico”: ho
immaginato di poter raccontare un linguaggio di
programmazione attraverso parole diverse, rispetto a
quello che io e i miei colleghi utilizziamo
quotidianamente.
Lo scopo di questo volume è quello di farvi incuriosire
nella programmazione: ho cercato di fornirvi tutti gli
strumenti per cominciare a giocare con Java, attraverso
l’uso dell’IDE e soprattutto attraverso la vostra fantasia e
voglia di mettervi alla prova.
In effetti avrei potuto riempire il libro di esempi di ogni
tipo, ma la rete è colma di esercitazioni, piccoli manuali,
tutorial: quello che invece vi chiedo ora è di studiare bene
quello che ci siamo detti in questo libro, per poi tuffarvi
in Internet e trovare problemi piccoli e grandi da
affrontare e risolvere.
Abbiate curiosità e voglia di studiare: le possibilità di un
linguaggio di programmazione ad oggetti sono pressoché
infinite, e tra l’altro Java è un mondo open source nel quale
troverete una quantità notevole di casi studio e librerie jar
da poter importare nei vostri progetti e usare nei vostri
esempi.
159
Io, come autore del libro, resto a vostra disposizione; e se
davvero vi state appassionando, vi consiglio di
approfondire il linguaggio, seguendo corsi o leggendo
manuali specifici sul linguaggio e sui suoi costrutti:
insomma non fermatevi a questo libro perché è solo un
antipasto per aprirvi l’appetito.
E fra un po’ di tempo, magari, ci rivedremo come
colleghi: sarò felicissimo di aver convinto qualcuno a
scegliere il mio stesso mestiere, di averlo convinto a
diventare un Analista Programmatore.
Un lavoro può essere bello o brutto, e dipende dalla
propria soggettività e dal contesto, ma c’è una
caratteristica dal lavoro dell’Analista Programmatore che
non deve sfuggire: nonostante sembri un mestiere freddo,
perché legato alle macchine, ai bit, ai numeri, in realtà è
un lavoro molto vicino alla filosofia e talvolta poetico.
Lo so che leggere l’aggettivo “poetico” vi avrà fatto
sorridere, immaginandolo un po’ eccessivo rispetto allo
sviluppo software; ma, per me, leggere le specifiche di un
cliente e svilupparle, realizzando un software proprio
come lui l’aveva immaginato, è un po’ come sentirmi
capace di poter realizzare i sogni di qualcuno.
E questo non vi sembra abbastanza poetico?
160