Fondamenti di Java - Home di homes.di.unimi.it

Lezione 1 - Il Linguaggio Java
Corso — Programmazione
Programmazione ad oggetti— Elementi di programmazione in
Java
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Java la nascita
• Green: Sun MicroSystems (James Gosling e Patrick
Naughton) per l’utilizzo in apparecchi di consumo tipo
Elettrodomestici intelligenti, cellulari (1991)
Indipendenza dall'architettura
• Il linguaggio era applicabile anche a sistemi client/server
per le sue ulteriori caratteristiche di real time, affidabilità
e sicurezza (1994)
• Browser HotJava: Poteva scaricare applet (programmi)
ed eseguirli sulla macchina client (1995)
• Netscape supporta Java (1996)
Crescita
• Grande crescita per semplicità d'uso e sintassi consolidata
(C)
• Grande librerie JDK (Java Development Kit) con
moltissime classi da riusare
• Nuova versione del linguaggio, chiamata Java2 (1998)
J2ME (piccoli dispositivi integrati) e J2EE (enterprise)
• Traino dello sviluppo di Internet
Sicurezza: le applet devono esserlo avviandosi sui client
in automatico
Trasferibilità: esecuzione su qualsiasi piattaforma
(diverso da portabilità)
Java: specificità(1)
• Java e’ un OOP completamente a oggetti (tutto in Java è
un oggetto)
• Non è permesso allocare e deallocare memoria
manualmente
• Sfrutta la garbage collection
• Non esistono i puntatori e la loro aritmetica ma solo
riferimenti
• Non esiste ereditarietà multipla (gestione con interfacce)
• Non esistono header file
Java: specificità(2)
• Oggetti persistenti: Serializzazione degli oggetti
• Facilmente distribuibile
• Indipendente dall'HW tramite la generazione di byte-code
eseguibile da una Java Virtual Machine
• Supporto a programmazione multithread e
multiprocessore
• Massima portabilità per indipendenza di tipi dalla
macchina
Java il programma
• I programmi suddivisi in “classi” descritte all’interno di file
con estensione “.java” (una sola classe per file)
• Il nome file “.java” deve coincidere con il nome della
classe
public class HelloWorld {
public static void main(String[] args) {
System.out.println(“Hello World”);
}
}
Dal programma all'esecuzione
• Codice della classe “.java” compilato nel bytecode “.class”
javac HelloWorld.java
• Macchina virtuale come strato aggiuntivo tra il bytecode e
la macchina vera
java HelloWorld.class
Macchina virtuale
• Astrae un elaboratore generico
• Il file “.class” contiene il bytecode e la tabella dei simboli
(tutto il necessario per una esecuzione)
• La macchina virtuale si occupa di:
Caricare le classi dal disco
Verificare la consistenza del codice
Eseguire il programma
Lezione 2 - Classi, Oggetti e variabili
Corso — Programmazione
Programmazione ad oggetti— Elementi di programmazione in
Java
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Classi e Oggetti
• L’unità minima di programmazione Java è la classe, ma un
programma potrebbe usare più classi
• Un oggetto viene creato istanziando una classe con
l'istruzione new seguita dal costruttore da utilizzare
• Il nome del costruttore coincide con il nome della classe
mentre i suoi parametri determinano quale costruttore
chiamare, esiste sempre il costruttore di default
• La new viene usata in una espressione di creazione
dell'oggetto e come tale definisce:
Tipo: la classe dell'oggetto
Valore: il riferimento all'oggetto instanziato
Oggetti
• Costruttore non indica un tipo di ritorno (posso avere
molti costruttori)
• Sull'oggetto si opera attraverso il riferimento
• La memoria associata ad un oggetto contiene lo stato
dell'oggetto e quello che serve alla JVM per gestire
l'oggetto
Variabili riferimento
• Devono avere un tipo compatibile con il tipo del
riferimento (liskov)
• Dichiarate prima del loro utilizzo
• Essendo variabili locali vivono nel blocco che è in
esecuzione
• Le variabili si trovano nello stack mentre gli oggetti nello
heap
• Posso avere riferimenti multipli allo stesso oggetto
• Non tutte le variabili contengono riferimenti ma quelle di
tipo primitivo contengono direttamente il valore
• Un riferimento importato a null perde la referenza alla
memoria
Oggetti e riferimenti
• Noto un riferimento posso chiamare i metodi dell'oggetto
riferito
• La chiamata di un metodo è analoga alla chiamata di una
funzione
• I parametri dei metodi vengono gestiti nel seguente modo
Tipi semplici passati per valore
I riferimenti vengono copiati per valore e permettono di
agire sull'oggetto riferito da dentro il metodo
I metodi possono avere dei valori di ritorno
Cerchio c = new Cerchio();
c.setRaggio(2.0);
double perimetro=c.Perimetro();
Metodi e Attributi
• Un metodo opera liberamente sull'oggetto a cui
appartiene con lo scopo di modificarne lo stato
• Invocazione di metodi di oggetti conosciuti
• Metodi specifici per agire su attributi (getter, setter)
• Lo stato è determinato dagli attributi che possono a loro
volta essere semplici o complessi (riferimenti ad oggetti)
Esempio
• Situazione in memoria con oggetti che hanno attributi
complessi
Oggetto e accessibilità
• Un oggetto è accessibile fin tanto che esiste un
riferimento che permette l'accesso
• Java controlla quali oggetti hanno dei riferimenti attivi e
quali no per decidere la loro deallocazione (garbage
collection)
• Essendo i riferimenti inseriti in variabili cessano di esistere
con esse, o quando queste vengono poste a null
Visibilità di metodi e attributi
• Permettono di modulare l'incapsulamento sulle esigenze
• Private: accessibile solo da altri metodi appartenenti alla
stessa classe
• Public: utilizzabile da metodi di qualsiasi classe
• Non specificato: accessibile alle altre classi dello stesso
package (in java un gruppo)
• Protected: visibile solo dalle classi dello stesso package
e dalle sottoclassi
• Protected non può essere utilizzato per definire la visibilità
di una classe
• Se non indicata la visibilità di una classe è solo interna al
package
Attributi Static
• Keyword già incontrata
• Ogni oggetto evolve in maniera indipendente anche se
istanza della stessa classe
• Se si vuole mantenere un attributo in comune per ogni
oggetto di una classe si definisce come static
• Si conserva il valore di un attributo statico in un blocco di
memoria separato ma relativo alla classe
• Questa caratteristica permette l'accesso ad attributi statici
anche in assenza di un istanza della classe (un oggetto)
• Si usa il nome della classe per selezionare l'attributo
statico
• Gli attributi statici vanno inizializzati non può farlo un
costruttore
Metodi Static
• Non si riferiscono a nessun attributo specifico di un
oggetto
• Equivalgono a procedure e funzioni di altri linguaggi
• Gli attributi si invocano con il nome della classe
• Esempio: classe Math che contiene metodi statici per
funzioni matematiche standard
• Esempio: Classe System che contiene come attributi
statici, oggetti che modellano interazioni con la console di
sistema (System.in o .out)
Tipizzazione in Java (1)
• E' un linguaggio fortemente tipato, il tipo di ogni
espressione è noto in fase di compilazione
• La compilazione controlla la compatibilità tra tipi e
effettua eventuali conversioni implicite
• Espressioni che coinvolgono riferimenti possono produrre
come risultato un tipo riferimento a loro volta (con l'eusilio
di eventuali conversioni implicite di tipo)
• Tipi primitivi: contengono direttamente il valore (short,
int, char, boolean, float, double)
• Tipi riferimento: contengono il riferimento all'oggetto
(classi, interfacce, array)
• Letterale null: valore assegnabile ad una variabile di
tipo riferimento indicante l'assenza del riferimento
Main Java
• Non potendo esistere alcun oggetto quando il programma
parte deve essere per forza static
• Deve essere un metodo pubblico
• Non ritorna nulla di particolare al chiamante ed è quindi
void
• public static void main(String[ ] args)
Lezione 3 - Classe String
Corso — Programmazione
Programmazione ad oggetti— Elementi di programmazione in
Java
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Classe String
• Classe che rappresenta sequenze immutabili di caratteri
• Esempio: String s= “Hello World” ;
• Presenta molti metodi per il confronto la ricerca
concatenazione ecc.
• Può essere scritto anche come String s= new
String(“Hello World”);
Metodi(1)
• public boolean equals(String s): Torna True se s
contiene gli stessi caratteri dell' oggetto corrente
• public boolean equalsIgnoreCase(String s): stessa
cosa trascurando le maiuscole
• public int indexOf(String s): Torna la posizione nella
stringa corrente in cui inizia la stringa s (se non esiste
torna -1)
• public String concat(String s): Concatena la stringa
corrente con s e ne torna una nuova (operatore +
abbrevia concat)
Metodi(2)
• public String toUpperCase(): torna una nuova stringa
di tutte maiuscole
• public String replace(char oldChar, char newChar)
torna una nuova stringa dove tutte le occorrenze di
oldChar sono sostituite con newChar
• public String substring(int beginIndex, int
endIndex): Nuova stringa sottostringa della corrente
delimitata da begin e end Index
• public int length(): Lunghezza in caratteri della stringa
corrente
Confronti
• I confronti tra tipi riferimento avvengono con operatori
tipo == e controllano se si fa riferimento allo stesso
oggetto
• Esistono metodi specifici per determinare se due oggetti
sono uguali (x.equals(y))
String a, b;
a = new String(ciccia);
b = new String(ciccia);
• I due riferimenti sono diversi, si riferiscono ad oggetti
differenti
• a.equals(b) ritorna vero essendo l'oggetto a identico
all'oggetto b
Esempi
String a = “hello”;
String b= a.toUpperCase();
boolean c= b.equals (a); quale sarà il risultato?
int i= b.length();
int j= b.indexOf(“LL”);
String d=a.substring(j,i);
char c=a.charAt(0);
String nome = “Marco”;
String saluti = “Buongiorno”.concat(nome.concat(“!!!”));
Lezione 4 - Array e collezioni
Corso — Programmazione
Programmazione ad oggetti— Elementi di programmazione in
Java
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Array
• Array in Java sono oggetti che incapsulano sequenze
ordinate di dati dello stesso tipo (tipo base)
• Hanno dimensione fissa, definita all’atto della creazione
• Sintassi semplice per accedere ai singoli elementi
• Il tipo base può essere sia primitivo che riferimento
• Costruzione: new tipo base[dimensione]
• Dichiarazione: Tipo base[] identificatore
Array di tipi primitivi
• Modellano sequenze di tipi elementari (interi, reali,
caratteri, booleani)
Array di oggetti
• String[] nomi = new String[4]
• Nelle posizioni ho null in fase di creazione
• nomi[0] = new String(“Marco”)
Array inizializzazioni e cicli
• Si può inizializzare all'atto della creazione come in C
• Si può inizializzare con dei cicli tipo classico ciclo for
• Si può usare un for-each
for (tipo base identificatore: array)
istruzione
• Esempio:
for (String n: nomi)
out.println(n);
Array multidimensionali
• È anche possibile creare matrici
• int [ ] [ ] matrice= new int [4] [4];
• Il primo indice si riferisce alla riga, il secondo alla colonna
• Non c’è limite al numero di dimensioni dell’array
(dimensione massima della memoria)
Main Java: argomenti
• public static void main(String[ ] args)
• Riceve come argomento il riferimento ad un array di
stringhe
• Quando in esecuzione la JVM cerca nel bytecode della
classe un metodo statico main
• Se lo trova, lo invoca passandogli come argomento il
riferimento all'array contenente le stringhe specificate nel
comando di esecuzione
• altrimenti l'array sarà vuoto (args.length sarà 0)
class Repeat {
public static void main(String[] args) {
for (String s : args)
System.out.print(s);
}
}
Classi Generiche(1)
• La Programmazione generica consiste nella creazione di
costrutti di programmazione che possano essere utilizzati
con tipi di dati diversi
• In Java si può raggiungere tale obiettivo usando
opportunamente l’ereditarietà (uso dell'oggetto object)
oppure le variabili di tipo e le classi generiche (esempio
LinkedList<String> del pacchetto java.util)
• Esempio: Classe Sequence che realizza sequenze non
ordinate di oggetti Sequence<E>
E viene detto tipo parametro
Possiamo dire che la classe o il tipo ``Sequence di E''
Sequence<String> seq = new Sequence<String>()
• Sono chiamati tipi parametrizzati
• I metodi di tali classi sono definiti usando il tipo
parametro es public boolean add(E o)
• Il for-each può essere usato per questi oggetti
Sequence<E> seq; for (E el: seq)
Classi Generiche(2)
• Si possono usare qualunque tipo riferimento per istanziare
il tipo parametro E
• Non si può usare uno dei tipi di dati primitivi
• Il tipo di dato che indicate va a sostituire la variabile di
tipo utilizzata nella definizione dell'interfaccia o della
classe generica
• Le variabili di tipo rendono più sicuro e di più facile
comprensione il codice generico
• Vedremo le conseguenze in seguito
Tipi enumerativi(1)
• Elencano dei valori possibili
• E' un tipo speciale di classe (keyword enum al posto di
class)
• I possibili valori del tipo sono stabiliti all'atto della
definizione del tipo
• I valori di tipo enumerativo sono riferimenti ad oggetti
• Le variabili di tipo enumerativo sono variabili riferimento
• Non si creano istanze di tipo enumerativo ma si possono
solo usare (sono già istanziati)
• Metodi comuni agli enumerativi sono:
public String name(): Restituisce il nome della costante
enumerativa.
public int ordinal(): Restituisce il numero ordinale del
valore enumerativo che esegue il metodo (primo alla
posizione 0)
Tipi enumerativi(2)
• Esempio: Enumerativo che identifica i giorni della
settimana enum GiornoSettimana
{LUN,MAR,MER,GIO,VEN,SAB,DOM};
• Posso definire enumerativi più complessi
• Come per le classi posso definire dei metodi per un
determinato enumerativo
• Esempio: public GiornoSettimana successivo()
GiornoSettimana g = GiornoSettimana.LUN;
out.println(g.ordinal()); 1
out.println(g.name()); LUN
Esempio
• Direzioni da prendere come enumerativi con metodo
particolare per prendere la direzione opposta
public enum Direzione {
Nessuna, Nord, Sud, Est, Ovest;
public Direzione getOpposta(){
switch (this) {
case Nord: return Sud;
case Sud: return Nord;
case Est: return Ovest;
case Ovest: return Est;
default: return Nessuna;
}
}
}
Lezione 5 - Ereditarietà in Java
Corso — Programmazione
Programmazione ad oggetti— Elementi di programmazione in
Java
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Ereditarietà
• Si definisce una classe derivata attraverso la parola chiave
``extends'' seguita dal nome della classe base
• Gli oggetti della classe derivata sono, a tutti gli effetti,
estensioni della classe base
• Anche nella loro rappresentazione in memoria lo abbiamo
visto anche in RAPTOR
• Ogni classe può estendere al più una superclasse
• Esiste un albero delle gerarchie Java dove si ha una radice
comune nella classe Object
Costruzione(1)
• L'istanza di una classe derivata si realizza a partire dalla
costruzione dell' oggetto base
• Di solito ci pensa il compilatore a chiamare il costruttore
della classe base come prima istruzione di ogni costruttore
della classe derivata
• Tale costruttore anonimo della superclasse si può anche
richiamare in modo esplicito, attraverso il costrutto
super(…)
Costruzione(2)
file Persona.java
class Persona {
Private String nome; String cognome;
Persona(String n, String c) {
nome = n;
cognome= c;
}
}
file Professore.java
class Professore extends Persona {
Private String Istituto;
Private String [] Corsi;
Professore(String n, String c,String ist) {
super(n,c);
Istituto= ist;
}
}
Accesso alla superclasse
• L' oggetto derivato contiene tutti i componenti (attributi e
metodi) dell' oggetto da cui deriva
• I suoi metodi non possono operare direttamente su quelli
definiti privati
• Questa restrizione può essere allentata usando la visibilità
``protected''
• Metodi si possono ridefinire spesso con lo scopo di
perfezionarli e non sostituirli
Esempio
file Base.java
class Base {
Private int attr1;
int Metodo() {
return attr1;
}
}
file Derivata.java
class Derivata extends Base {
Private int attr2;
int Metodo() {
return super.Metodo()+attr2;
}
}
Compatibilità formale
• L'istanza di una classe derivata è formalmente
compatibile con il tipo della sua super-classe Base a =
new Derivata( );
• Il tipo Base di a limita le operazioni di Derivata, se non
fosse così viene generato un errore in compilazione
• Esempio aggiungiamo alla classe Derivata un metodo int
Ciccia();
Base b1= new Base();
Base b2= new Derivata();
Derivata d= new Derivata();
b1.Metodo(); (OK)
b2.Metodo(); (OK)
b2.Ciccia(); (ERRORE)
Polimorfismo(1)
• Java mantiene traccia della classe effettiva di un dato
oggetto così da seleziona sempre il metodo più specifico
anche se la variabile che lo contiene appartiene ad una
classe più generica
• Una variabile che rappresenta una classe generica può
avere ``molte forme''
• Contenere oggetti di sottoclassi differenti
• In caso di ridefinizione, il metodo chiamato dipende dal
tipo effettivo dell' oggetto
Base B = new Derivata();
B.Metodo(); Quale metodo vienen chiamato?
Polimorfismo(2)
• Questa tecnica si può sfruttare definendo, nella
super-classe, metodi con implementazione generica poi
sostituiti, nelle sottoclassi, da implementazioni specifiche
• Si utilizzano variabili aventi come tipo quello della
super-classe
• Meccanismo alla base di molti ``pattern'' di
programmazione
• A volte implementato esplicitamente usando i metodi
astratti
Forma f1 = new Cerchio();
Forma f2 = new Rettangolo();
double area1,area2;
area1=f1.area();
area2=f2.area();
La classe Object
• Se non viene definita esplicitamente una super-classe, il
compilatore usa la classe predefinita Object la quale non
ha super-classe essendo la radice della gerarchia
• Object definisce un certo numero di metodi pubblici
• public boolean equals(Object o): già visto ecco da
dove deriva la possibilità di usarlo. Va ridefinito per ogni
sottoclasse
• public String toString(): Restituisce una
rappresentazione stampabile dell' oggetto
• public int hashCode(): Restituisce un valore intero
legato al contenuto dell' oggetto
Controllo dell'ereditarietà
• Può risultare utile impedire esplicitamente l’utilizzo della
tecnica del polimorfismo
• Esempio: per motivi di sicurezza o per garantire il
mantenimento di una data proprietà del sistema
• Keyword final
Metodo: non può essere ridefinito da una sottoclasse
Classe: non può avere sottoclassi
Attributo: non può essere modificato (non centra
l'eredità)
• Se si vuol rendere il polimorfismo obbligatorio si usa la
keyword abstract
• Se ho metodi astratti la classe deve essere astratta a sua
volta
• Una classe abstract per essere istanziata occorre
definirne una sottoclasse che implementi i metodi
mancanti
Interfacce
• Una classe astratta può contenere metodi non astratti
• Se si vogliono definire metodi astratti senza vincolare la
gerarchia di ereditarietà delle classi che li
implementeranno si utilizzano le interfacce (implements)
• Insiemi di metodi pubblici astratti e costanti (attributi
static final)
public interface Comparable {
public int compareTo(Object o);
}
public class Cerchio extends Forma
implements Comparable {
public int compareTo(Object o) {
}
}
Interfacce e tipi
• Una interfaccia definisce un tipo
• Un oggetto può implementare più interfacce e quindi
avere più tipi
• Si può verificare se un oggetto ha un dato tipo con
l'operatore ``instanceof''
• Alcune interfacce non hanno metodi
• Servono solo come ``marcatori'' per indicare che gli
oggetti delle classi che le implementano godono di
qualche proprietà
Gerarchie e tipi
• E' possibile assegnare a una variabile il cui tipo sia una
classe un riferimento a un oggetto di una sottoclasse
• Object o = new String(“ciccia”);
• Non è possibile assegnare (direttamente) a una variabile
del tipo della sottoclasse un riferimento della superclasse
• Object o = new String(“ciccia”); String s = o;
• Posso effettuare un cast esplicito: String s = (String)o;
Interfacce e tipi generici
• Esempio: Interfaccia Comparable<T>: Specifica un unico
metodo il cui scopo è quello di definire un ordine totale
sugli oggetti dei tipo che la implementano
Metodo: public int compareTo(T o): Confronta l'oggetto
che esegue il metodo con quello specificato
• Differente rispetto alla definizione data in precedenza che
sfruttava la classe Object
• Esempio: public class String implements
Comparable<String> implementando il metodo
compareTo(T o) con String al posto di T
Interfaccia Iterable<E>
• Interfaccia generica Iterable<E>
• Ogni classe che implementa Iterable rappresenta una
collezione di dati che può essere iterata, cioè scandita, un
elemento alla volta, mediante l'uso di un oggetto che
viene detto iteratore
Metodo: public Iterator<E> iterator(): Restituisce un
iteratore degli oggetti presenti nella collezione che esegue
il metodo
• Iterator<E> ha metodì già visti hasNext() e next()
Tipi generici
• Come tutti i tipi riferimento, anche i tipi generici e i relativi
tipi parametrizzati si collocano all'interno della gerarchia
dei tipi
• Le relazioni fra i tipi parametro non inducono relazioni sui
relativi tipi parametrizzati
• wildcard <?> funge da segnaposto per un tipo che non è
ancora noto al momento della compilazione
• Sequence<?> è supertipo di tutti i tipi parametrizzati
ottenibili da sequenza
• E' possibile limitare l'insieme dei tipi sostituibili al
segnaposto a una parte della gerarchia
• Esempio: <? extends Comparable<E>>
Lezione 6 - Packages
Corso — Programmazione
Programmazione ad oggetti— Elementi di programmazione in
Java
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Package(1)
• Raggruppare in unità logiche classi, interfacce correlate
tra loro
• File che contengono classi Java
• Questi package possono essere memorizzati in file
compressi chiamati file JAR
• Unità di compilazione: file che contengono codice
sorgente Java.
• Ogni unità può contenere al più una classe o un'interfaccia
dichiarata public
• La classe o interfaccia dichiarata pubblic determina il
nome del package
Package(2)
• Un'unità di compilazione è aggiunta ad un package
mediante l'istruzione package nome package
• Deve obbligatoriamente essere la prima istruzione
nell'unità di compilazione
• Esempio: se volessimo aggiungere la classe Derivata ad
un package prog.utility
• Inserire package prog.utility all'inizio del file
Derivata.java
Esempio
• la seguente classe si compila come javac Prima.java, il
nome completo della classe pack.Prima
• Posso usare il nome completo per omettere la direttiva di
importazione del pacchetto
• Le direttive di importazione aggiungono lo spazio dei nomi
di un package a quanto il compilatore prende in
considerazione
package pack;
public class Prima {
public String toString(){
return “classe pack.Prima”;
}
}
Import
• L'importazione avviene con import nome del package
• Posso usare il carattere *
• Aggiungono allo spazio dei nomi, i nomi di tutte le classi e
di tutte le interfacce presenti nel package
• Il compilatore importa automaticamente le classi e le
interfacce del package java.lang e del package di default
• Package di default: definito automaticamente, senza
nome, che include tutte le classi e tutte le interfacce
definite nella directory di compilazione che non sono
esplicitamente incluse in un package
Protezione d'accesso
• Uno degli obiettivi del package è proprio quello di fornire
un ambiente di protezione
• Le classi appartenenti ad un package possono accedere
altre classi ed in generale membri con accesso default e
membri con accesso protected
• Default: non viene specificato nessun modificatore
d'accesso durante la dichiarazione del membro (chaimato
anche livello amichevole, ovvero visibile dal package)
• Classi contenute in altri package non possono accedere a
classi o membri con accesso default
• Membri protected possono essere usati da classi in altri
package che siano state dichiarate sottoclassi della classe
in questione
Package Java
• java.lang: funzionalità di base del linguaggio e tipi di
dato fondamentali
• java.util: classi di collezione (Strutture dati)
• java.io: operazioni su file
• java.math: aritmetica multiprecisione
• ...
Lezione 7 - Eccezioni
Corso — Programmazione
Programmazione ad oggetti— Elementi di programmazione in
Java
Marco Anisetti
e-mail: [email protected]
web: http://homes.di.unimi.it/anisetti/
Università degli Studi di Milano — Dipartimento di informatica
Affidabilità(1)
• Un processo è un programma che esegue una sequenza di
operazioni
• Alcune in maniera diretta altre attraverso funzionalità di
sistema operativo
• In alcuni casi una operazione non può essere eseguita
• Lo si scopre a run-time
• Il programma deve potersi accorgere di questi eventi e
impostare una reazione
Affidabilità(2)
• Per quali motivi può avvenire un errore runtime:
• Mancanza di risorse: Memoria esaurita, disco pieno,
autorizzazioni insufficienti ecc.
• Parametri errati: Divisione per 0, riferimenti a risorse
inesistenti ecc.
• Sequenza di operazioni illecita: Utilizzo di riferimenti
nulli, scrittura su file già chiuso ecc.
• Alcune situazioni dipendono dal programmatore altre dal
contesto di esecuzione
• Questi eventi (chiamati eccezioni) provocano uno stato
incoerente nel programma
• Per garantire l’affidabilità del sistema, occorre saper
rilevare e gestire le eccezioni
Strategie
• Tutte le operazioni che sono a rischio fallimento
dovrebbero indicare:
• Se sono terminate con successo o meno
• L’eventuale anomalia riscontrata
• Un modo per farlo è far in modo di gestire i valori di
ritorno verificandoli (lo fanno alcuni linguaggi)
• il diagramma di flusso teorico si complicherebbe
notevolmente
• Se non si inseriscono tutti i test del caso si potrebbe
compromettere la capacità di valutare l’integrità del
sistema
Complessità e contesto
• Il codice associato ad una procedura semplice molto
rapidamente ingestibile
• Normalmente quello che si fa è omettere i test
• Ma cosa fare quando si rileva un malfunzionamento?
• Spesso, ci si accorge dei fallimenti all' interno di
procedure generiche e non si riesce ad individuare le
contromisure necessarie
• Occorrerebbe segnalare il malfunzionamento al chiamante
fornendo la descrizione di quanto successo (eccezione)
• Il chiamante può gestire l’eccezione o rimandarne la
gestione al proprio chiamante ricorsivamente
Eccezioni in Java(1)
• Java utilizza un'insieme di classi per modellare l’anomalia
• La classe principale è la classe Throwable
• Contiene meccanismi per Segnalare, Gestire,
Propagare
• I meccanismi sono ottenuti attraverso la catena di
invocazione dei metodi
Eccezioni in Java(2)
• Un metodo che può fallire deve segnalarlo nella propria
dichiarazione di classe
• Si usa la keyword “throws” seguita dal tipo (o dai tipi) di
eccezione che si può verificare durante l’esecuzione
• Chi invoca il metodo gestisce l'anomalia attraverso il
costrutto “try” / “catch”
• Se non è in grado la propaga a sua volta attraverso la
generazione la stessa anomalia verso il chiamante
Esempio
• Throws identifica che può fallire
• If per verificare la coerenza
• throw interrompe l'esecuzione del metodo
• Exception(“div 0”) descrizione dell'eccezione
double div(int num, int den)
throws Exception {
if (den==0)
throw
new Exception(“div 0”);
return num/den;
}
Try/Catch
• Costrutto utilizzato per il controllo delle eccezioni comune
ad altri linguaggi
• Seleziona le parti di codice che possono provocare
anomalie
try{
<codice da controllare>
} catch(Exception e){
<gestione anomalia>
}
Try/Catch
• È possibile reagire in modo differente a tipi diversi di
eccezioni mettendo più clausole “catch” in sequenza
• Finally indica le istruzioni che devono essere eseguite
comunque
try{
} catch(Exception e1){
} catch(Exception e2){
} finally {
}
Problemi
• Il codice del blocco catch selezionato dovrebbe ripristinare
la coerenza nel sistema ma non è detto che si possa
• Eccezione dentro una eccezione complicando la
programmazione
• A volte si stampa soltanto il fatto che si è trovata
l'eccezione per debug
• Si lancia un'altra eccezione aggiungendo dati di contesto
(data e ora di esecuzione ecc)
• Rilanciare la stessa eccezione avendo compiuto qualche
azione a margine
• Correggere anomalia (ciclo che include try catch dove
avviene la correzione e viene riprovata l'azione)
• Ripristinare lo stato precedente con le istruzioni di catch
• Interrompere l'esecuzione
Modellazione delle eccezioni
• Anomalia descritta come oggetto di tipo Throwable
• Classe base della gerarchia delle eccezioni
• Metodi per la gestione dell'anomalia
• Le sottoclassi modellano tipi differenti di anomalie
• String getMessage(): Restituisce la stringa che descrive
l’anomalia
• void printStackTrace(): Stampa la posizione in cui si è
verificata l’eccezione e la sequenza dei metodi chiamanti
ad essa relativi
Tipologie di anomalie
• Errori della macchina virtuale (classe error): non
possono essere recuperati (memoria esaurita stack
overflow)
• Errori di programma (classe Exception): gestiti in modo
esplicito, dichiarandone l’eventualità nei metodi che li
possono generare (uso costrutto try catch)
• Si possono definire delle classi per eccezioni
personalizzate, solitamente non contengono metodi ne
attributi
• Due costruttori, uno anonimo che associa all’oggetto una
descrizione generica, uno con una stringa che permette di
dettagliare l’ avvenuta anomalia
Conclusioni
• Eccezioni come soluzione a problemi che si scatenano
run-time
• Permettono di evitare complicazioni nel codice
• Permettono di gestire errori che si verificano in parti di
codice definite da blocchi try catch
• Si tratta comunque di codice da scrivere e che potrebbe
comunque non essere in grado di gestire l'errore
• Non implementare la gestione delle eccezioni non è mai
una idea buona