Parte II: classi e oggetti ! Metodi ! Classi e oggetti µ Generalità µ Classi particolari predefinite: • Stringhe • Array µ Tipi riferimento • Copia di oggetti e array • Confronto tra oggetti e array ! Package ! Programmazione a oggetti in Java ! Struttura generale di un file Java ! Eccezioni 1: Introduction 1 Metodi ! Metodo: sequenza di istruzioni Java dotata di nome (equivalente a una funzione in C) ! Può essere invocato da altro codice Java, passandogli 0 o più argomenti, come una chiamata a funzione ! Restituisce un valore (eventualmente void) ! Ogni metodo è definito all’interno di una classe ! Nota: il passaggio dei parametri avviene per valore 1: Introduction 2 Metodi/2 ! Firma (signature) del metodo: <modificatore> <tipo> <nome> (<lista parametri>) [throws <eccezioni>] ! Modificatori: µ Accesso: public, private. protected, package µ static µ final ! Lista parametri: significato analogo a C/C++ ! Tipi di eccezione che il metodo può lanciare (opzionale) ! Sono possibili più metodi con lo stesso nome overloading ! Corpo del metodo: sequenza di istruzioni racchiuse tra parentesi graffe 1: Introduction 3 Classi ! Struttura dotata di nome che implementa un tipo di dato ! Contiene variabili e costanti (di classe) e metodi ! Variabili di classe e metodi sono detti membri della classe ! Più di 1500 classi predefinite in Java, organizzate in package 1: Introduction 4 Classi, istanze, oggetti Nel seguito: ! Oggetti (istanze di classe) ! Come istanziare classi già esistenti ! Due importanti classi Java: ! ! µ String µ Array Tipi per riferimento (dove si nascondono i puntatori) µ Copia di oggetti e array µ Confronto tra oggetti e array Package 1: Introduction 5 Oggetti e istanze ! ! Oggetto: valore di un tipo di dato classe ! ! Dichiarazione: Point p; ! ! Definisce una nuova variabile p di tipo Point, dove Point è una classe La lista di parametri è opzionale ! Point p = new Point(2,5) va bene ! Inizializzazione: <identificatore> = new <nome classe> (<lista parametri>) Inizializzazione: La sola dichiarazione non crea l’oggetto!! new serve a invocare il costruttore della classe, come vedremo più avanti ! p = new Point(2,5); ! Sintassi simile a C++ ! Nota: la lista dei parametri è opzionale (dipende dal costruttore), le parentesi 1: Introduction tonde sono necessarie 6 La classe primoEsempio import java.io.*; public class primoEsempio { public static void main(String args[]) { String nomeCorso, nomeDocente; /* Variabile locale (di metodo) */ docente docenteReti; docenteReti = new docente(); nomeCorso = docenteReti.insegnamentoDocente(); nomeDocente = docenteReti.nomeDocente(); System.out.println("Nome del corso: " + nomeCorso); System.out.println("Nome del docente: " + nomeDocente); } } /* Fine classe primoEsempio */ class docente { /* Non può essere pubblica */ private String nomeDocente = "Luca Becchetti"; /* Variabile di classe */ private String corsoDocente = "Reti di Calcolatori"; public String nomeDocente() { return nomeDocente; } public String insegnamentoDocente() { 1: Introduction 7 return corsoDocente; } } /* Fine classe docente */ Classe String ! ! Rappresenta stringhe µ Classe predefinita µ Mette a disposizione vari metodi utili (controllarli!!) µ Gli oggetti di questa classe rappresentano stringhe non modificabili L’inizializzazione ammette anche la sintassi seguente: String nome = “Pippo”; /* String nome = new String(“Pippo”); */ ! Molti metodi utili: µ nome.length() restituisce la lunghezza (No. caratteri) della stringa contenuta nell oggetto nome µ Molti metodi consentono di manipolare stringhe µ Consiglio: studiare la documentazione sulla classe (ci si può arrivare dal Tutorial) µ Vedere anche la classe StringBuffer (come String, ma consente 1: Introduction di rappresentare stringhe variabili) 8 Array ! Lista indicizzata di valori dello stesso tipo ! Valori appartenenti a: ! µ Tipi primitivi µ Tipi riferimento (Oggetti, stringhe, array) Dichiarazione di array: !"#$%%%!&% )+(,(#(-* !"#$./%%%%%%%0++0"12(1!"#$&% % !"#$././%%%%0++0"12(1%0++0"12(1!"#$&% 3*(4#./% % % % % 0++0"12(13*(4#&% % 56077$%3*(4# ! %''%#()* % %''%#()*%0++0" %''%#()*%0++0" % ''% #()*% 2( Sintassi alternativa (tipo C/C++): 3*(4#%%%%%0++0"12(13*(4#./& Attenzione: la dichiarazione non alloca memoria per l’array!! 1: Introduction 9 Array/2 ! Creazione di array: µ ! ! Si può usare l’operatore new con questa sintassi: String[] lines = new String[50]; /* Crea un array di 50 stringhe */ /* Attenzione: alloca la memoria per contenere 50 riferimenti a oggetti di classe String!! */ L’array creato ha dimensione fissa (es.: 50 oggetti di tipo String nell’esempio precedente) Dopo la creazione, le componenti dell’array sono inizializzate a valori di default che dipendono dal tipo base µ false per boolean µ 0 per int µ 0.0 per float µ null per oggetti 1: Introduction 10 Array/3 Creazione e inizializzazione: ! int[] multipli_di_due = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}; Viene creato un array di 10 interi. Si può usare la stessa sintassi con oggetti ! multipli_di_due[2] restituisce 6 (gli iniziano da 0, come in C) ! La lunghezza di un array è definita con la sua creazione e ne è una proprietà intrinseca. ! Se: String[] lines = new String[50]; Allora lines.length restituisce 50 ! ! .length non è un metodo -> niente parentesi tonde!! ! Può essere usato soltanto con gli array!! 1: Introduction 11 Array multidimensionali ! Per creare un array multidimensionale occorre specificare almeno la dimensione più a sinistra ! Se si specificano più dimensioni, devono essere quelle più a sinistra int[][][] matrice3D = new int[10][20][30]; // GIUSTO int[][][] matrice3D = new int[10][][]; // GIUSTO int[][][] matrice3D = new int[10][20][]; // GIUSTO int[][][] matrice3D = new int[][20][30]; // SBAGLIATO !!! int[][][] matrice3D = new int[10][][30]; // SBAGLIATO !!! ! Creazione e inizializzazione esplicita di array (senza new): int[][] matrice2D = { {0,0}, int[][] matrice2D = { {0,0,0,0,0}, {0,1,2,3,4}, {0,2,4,6,8}, {0,3,6,9,12} }; {0,1,2,}, {0,2,4,6,8}, {0,3,6,9,12} }; 1: Introduction 12 Tipi per riferimento Tutti i tipi primitivi hanno dimensione (in byte) determinata e sono manipolati direttamente ! Array, stringhe e, in generale oggetti, non sono manipolati direttamente, ma attraverso puntatori ! Una variabile avente per tipo una classe (array, stringa) contiene in realtà un riferimento (puntatore) all’ oggetto (array, stringa) ! Se: ! Point p = new Point(2, 5); Allora p contiene un riferimento al nuovo oggetto di 1: Introduction classe Point creato 13 Tipi per riferimento/2 ! I riferimenti sono simili ai puntatori C/C++ ma non possono essere manipolati ! Conseguenze cui prestare attenzione: ! Copia tra variabili di tipo primitivo: int x = 42; int y = x; Alla fine sia x che y contengono il valore 42 ! Copia di oggetti: Point p = new Point(1,2); Point q = p; q e p contengono lo stesso riferimento e quindi puntano allo stesso oggetto!! Modificare q (ad esempio q.x = 3) significa modificare 1: Introduction l’oggetto originale 14 Tipi per riferimento/3 ! Per copiare array: si usa il metodo arraycopy() public class ArrayCopyDemo { public static void main(String[] args) { char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' }; char[] copyTo = new char[7]; System.arraycopy(copyFrom, 2, copyTo, 0, 7); System.out.println(new String(copyTo)); } } ! Per copiare stringhe basta usare il costruttore: String Stringa1 = “Io sono una copia”; String Stringa2 = new String(Stringa1); 1: Introduction 15 Tipi per riferimento/4 ! Per copiare oggetti si può usare il metodo clone(), ereditato dalla classe Object (vale anche per array e stringhe): int[] data = {1,2,3,4,5}; int[] copy = (int[]) data.clone(); Attenzione al cast!! ! ! ! L’oggetto può essere clonato solamente se la classe cui appartiene implementa l’interfaccia Cloneable (più avanti nel corso) Il clone di un oggetto contiene una copia di ogni valore primitivo e di ogni riferimento -> clone() non è ricorsivo Per copiare oggetti si possono anche copiare i singoli campi, uno a uno -> Attenzione ai riferimenti!! 1: Introduction 16 Tipi per riferimento/5 ! Confronto tra stringhe: String a = new String(“ciao”); String b = new String(“ciao”); ! ! a == b in generale restituisce false Bisogna usare il metodo equals(), ereditato dalla classe Object: if (a.equals(b)) System.out.println(“Vero!!”); ! Viene stampato Vero!! 1: Introduction 17 Package ! ! Collezione di classi dotata di nome (può contenere subpackage) java.lang è il package fondamentale del linguaggio Java. Contiene le classi principali, tra cui Object, String, ecc ! Tutte le classi del package c possono indicare classi dello stesso package usando solamente il nome ! Importando un package si possono usare i nomi abbreviati per le classi del package. Es.: import java.util.*; ……. Hashtable h = new Hashtable(); Altrimenti: java.util.Hashtable h = new java.util.Hashtable(); 1: Introduction 18 Struttura generale di un file .java ! 1 direttiva opzionale package ! 0 o più direttive import ! ! ! package mypackage; /* Specifica che questa classe appartiene a mypackage */ Una o più classi, di cui una sola pubblica import java.util.*; import java.io.*; Dopo la compilazione a ciascuna classe corrisponde un file .class separato, contenente il byte code public class classePrincipale { ….. } class secondaClasse { …. } class terzaClasse { …. } ……. Nome del file: classePrincipale.java Il nome del file deve essere quello della classe pubblica (estensione .java) 1: Introduction 19 Programmazione a oggetti in Java ! ! ! ! Membri di una classe µ Campi statici e istanza µ Metodi statici e istanza Creazione e inizializzazione di oggetti - costruttori Distruzione e finalizzazione di oggetti – garbage collection Sottoclassi e ereditarietà µ Classi final µ Gerarchia delle classi µ Shadowing µ Overloading µ Overriding 1: Introduction 20 Classe ! Struttura dotata di nome che implementa un tipo di dato ! Contiene variabili e costanti (di classe) e metodi ! Variabili di classe e metodi sono detti membri della classe 1: Introduction 21 1: Introduction 22 Struttura di una classe ! Campi (variabili di classe) ! Metodi ! Campi/metodi statici: µ µ Appartengono alla classe e non a un oggetto particolare Sono identificati dal modificatore static Struttura di una classe public class Circle { public static final double PI = 3.14159; // Campo statico (in questo caso una costante) public double r; // Campo istanza: il raggio di un cerchio public static double radiansToDegrees(double rads) { // Passa da radianti a gradi return rads*180/PI; } public double area() // Metodo istanza: calcola l’area di un cerchio { return PI*r*r; } public double circumference() // Metodo istanza: calcola la circonferenza di un cerchio { return 2*PI*r; } } /* Fine della classe */ 1: Introduction 23 Membri di una classe ! Modificatori di accesso: determinano la visibilità di membri di una classe µ private double r; /* Nella classe Circle */: solo oggetti della classe Circle possono accedere al campo r µ private double area() { /* Nella classe Circle */ return r*r*PI; } Solo oggetti della classe Circle possono accedere al metodo area() µ public: tutti gli oggetti, di qualunque classe, in qualunque package, possono accedere al campo/metodo µ protected: solamente oggetti di sottoclassi o classi appartenenti allo stesso package della classe possono accedere al campo/metodo µ package: solamente classi dello stesso package possono accedere al campo/metodo 24 1: Introduction Membri di una classe/2 ! Un campo/metodo istanza è privo del modificatore static. Appartiene all’istanza e non alla classe ! Campi: µ public double r; /* Nella classe Circle */ Ogni istanza della classe Circle possiede il proprio valore di r µ Se: µ Circle myCircle = new Circle(); µ Allora myCircle.r permette di accedere al valore del campo r di myCircle da altre classi (all’interno della classe Circle basta r) Metodi: Circle myCircle = new Circle(); myCircle.area() permette di accedere al metodo area() dell’oggetto da altri oggetti. area() può essere usato all’interno della classe in modo equivalente a this.area() ! 1: Introduction 25 Membri di una classe/3 ! ! ! ! Un campo statico è essenzialmente una variabile globale alla classe Qualunque oggetto di classe Circle ha la stessa copia della variabile PI PI può essere usata senza definire oggetti di classe Circle Bisogna usare Circle.PI da oggetti non appartenenti alla classe Circle, mentre si può usare PI da oggetti di classe PI: myClass myObject = new myClass(); Circle myCircle = new Circle(); myObject.a = PI; /* Sbagliato !! */ myObject.b = myCircle.PI: /*Corretto!! Anche: Circle.PI */ ! Attenzione: i campi statici sono inizializzati una volta sola, dal primo oggetto della classe creato 1: Introduction 26 Membri di una classe/4 ! Un metodo statico è associato alla classe, non a una particolare istanza ! Può essere usato senza creare un oggetto della classe: double d = Circle.radiansToDegrees(2.0); ! ! ! Un metodo statico può usare qualsiasi campo o metodo statico definito nella propria classe o in un’altra Un metodo statico non può usare campi o metodi istanza La classe java.lang.Math mette a disposizione metodi statici per le principali funzioni matematiche 27 1: Introduction Membri di una classe/5 class AnIntegerNamedX { int x; static public int x() { return x; } static public void setX(int newX) { x = newX; } } Errore: setX() è statico ma accede a x (variabile istanza) Modificatore static: ! Variabili: serve a definire una costante ! ! static double PI = 3.14; definisce una variabile di classe Se l’oggetto circle esegue l’istruzione: PI = 0; il valore di PI è posto a 0 per tutti gli oggetti di classe Circle ! Modificatore final: final double PI = 3.14; definisce una costante PI per ogni istanza della classe Circle ! final static double PI = 3.14; definisce una sola costante PI per ogni 28 1: Introduction istanza della classe Circle Creazione e inizializzazione di oggetti )8!6(5%56077%9(+56$%: % % )8!6(5% 7#0#(5% ;(406% 2*8!6$% 3<% =% >?@A@BC& 'D%90,)*%7#0#(5*!D' %%)8!6(5%2*8!6$%+& Costruttore: ! 'D%90,)*%(7#04E0%D' % % )8!6(5% 9(+56$F2*8!6$% +0GG(*H% :% 'D 9IJKLMKKILN%D' %'D%<4(E(06(EE0%(6%50,)*%(7#04E0%+%D' +% =% +0GG(*&% 'D% O45P$Q% #P(7?+% =% +0GG(*& D' %%R !% )8!6(5% 2*8!6$% 0+$0FH% % % % % :% 'D% S$#*2* (7#04E0%D' %%%%+$#8+4%3<D+D+& %%R )8!6(5% 2*8!6$% 5(+58,;$+$45$FH% :'D S$#*2*%(7#04E0%D' +$#8+4%TD3<D+& %%R R%'D%U(4$%2$660%56077$%D' Stesso nome della classe, senza tipo, perché un costruttore non ha valori di ritorno, neppure void ! Se non definito -> costruttore di default ! Il costruttore ha il compito di inizializzare l’oggetto this ! ! E’ possibile avere costruttori multipli, purché abbiano liste dei parametri diverse (overloading) Modificatori di accesso (private, public, protected, package): permettono di specificare quali oggetti possono creare istanze della classe 1: Introduction 29 Distruzione e finalizzazione di oggetti ! ! ! ! Garbage collection: quando un oggetto non è più usato (non esistono riferimenti ad esso) la sua memoria può essere liberata Finalizzazione: prima della garbage collection, la JVM invoca il metodo finalize() (valore restituito void) di un oggetto (ereditato da java.lang.Object). Se una classe implementa finalize(), allora le azioni previste nel metodo sono eseguite prima della garbage collection Nessuna garanzia sull’istante di invocazione di finalize() 1: Introduction 30 Sottoclassi e ereditarietà )8!6(5%56077%9(+56$%: % % )8!6(5% 7#0#(5% ;(406% 2*8!6$% 3<% =% >?@A@BC&% % 'D 90,)*%7#0#(5*!D' %%)8!6(5%2*8!6$%+& 'D%90,)*%(7#04E0%D' %%)+(-0#$%(4#%48,!$+I;9(+56$7&%%'D%3+(-0#*VVD' %%)8!6(5%9(+56$FH%:%'D9IJKLMKKILN%D' %% +=@& %%R % %)8!6(5%9(+56$F2*8!6$% +0GG(*H% :% 'D% 9IJKLMKKILN D' %'D%<4(E(06(EE0%(6%50,)*%(7#04E0%+%D' +%=%+0GG(*&%'D%O45P$Q%#P(7?+%=%+0GG(*&%D' %%R !%)8!6(5%2*8!6$%0+$0FH%%%%%:%'D%S$#*2*%(7#04E0%D' %%%%+$#8+4%3<D+D+& %%R )8!6(5% 2*8!6$% 5(+58,;$+$45$FH% :'D% S$#*2* (7#04E0%D' +$#8+4%TD3<D+& %%R R%'D%U(4$%2$660%56077$%9(+56$%D' public class planeCircle extends Circle { public double cx, cy; public planeCircle(double x, double y) { /* COSTRUTTORE */ /* Implicitamente: super(); */ cx = x; /* this.cy = y; */ cy = y; /* this.cy = y; */ } public static void main(String args[]) { Circle myCircle = new Circle(2.0); System.out.println(myCircle.area()); System.out.println(myCircle.circumference()); /* System.out.println(myCircle.numberOfCircles); Sbagliata perché numberOfCircles è privata alla classe Circle */ System.out.println(myCircle.r); planeCircle myPlaneCircle = new planeCircle(0.0, 0.0); /* System.out.println(myPlaneCircle.numberOfCircles); sbagliata perché numberOfCircles non è ereditata */ System.out.println(myPlaneCircle.r); System.out.println(myPlaneCircle.area()); System.out.println(myPlaneCircle.circumference()); } } 1: Introduction 31 Sottoclassi e ereditarietà/2 Cosa si eredita: ! Tutti i campi/metodi dichiarati public o protected ! Tutti i campi/metodi privi di modificatore di accesso, purché la sottoclasse appartenga allo stesso package della superclasse Cosa non si eredita: ! Membri dichiarati private Costruttori. Es.: PlaneCircle myPlaneCircle = new PlaneCircle(3.0); Sbagliato, perché PlaneCircle non eredita il costruttore di Circle ! ! Membri privi di modificatore di accesso, qualora la sottoclasse non appartenga allo stesso package della superclasse ! Variabili con lo stesso nome di variabili della sottoclasse (shadowing) ! Metodi con lo stesso nome di metodi della sottoclasse (overriding) 1: Introduction 32 Sottoclassi e ereditarietà /3 public PlaneCircle(double r, double x, double y) { super(r); this.cx = x; this.cy = y; } ! Il costruttore della sottoclasse usa quello della superclasse ! Prima istruzione: invocazione di un costruttore della superclasse ! ! ! ! ! La prima istruzione del costruttore di una sottoclasse deve sempre essere la chiamata di un costruttore della superclasse Se ciò non accade, il compilatore inserisce implicitamente una chiamata a super() Se non esiste un costruttore della superclasse che non accetta argomenti -> errore super indica la superclasse super() permette di specificare un costruttore 1: Introduction della superclasse 33 Sottoclassi e ereditarietà/4 I!W$5# 9(+56$ 3604$9(+56$ S0#P J"7#$, Object: ! Unica classe che non ha superclasse ! Ogni classe eredita i metodi di Object Classi final: ! L$02$+ <4)8#J#+$0,L$02$+ U(6$L$02$+ U(6#$+L$02$+ J#+(4GL$02$+ Non ammettono sottoclassi In figura: Sottoinsieme delle classi Java 1: Introduction 34 Sottoclassi e ereditarietà /5 Field Shadowing (Nascondere campi) C è sottoclasse di B che è sottoclasse di A. Tutte e tre le classi hanno un campo x. Siamo in C: Method overriding (ridefinizione) ! X%%%%%%%%%%%%%%%%%%''%90,)*%X%2(%9 #P(7?X%%%%%%%%%%%%''%90,)*%X%2(%9 78)$+?X%%%%%%%%%%%''%90,)*%X%2(%Y FFYH#P(7H?X%%%%%%%''%90,)*%X%2(%Y FFOH#P(7H?X%%%%%%%''%90,)*%X%2(%O 78)$+?78)$+?X% % % % % ''% JYOZ[<OKIQ% 4*4% 7( +(;$+(75$%06%50,)*%X%2(%O La variabile della sottoclasse nasconde quella della superclasse con lo stesso nome ! La sottoclasse definisce un metodo con gli stessi nome, lista parametri e tipo class A { int i = 1; int f() {return i;} } class B extends A { int i; // Questo campo nasconde il campo i di A int f() // Questo metodo ridefinisce il metodo f() di A { i = super.i + 1; // super.i è il campo i di A, ovvero A.i return super.f() + i; // super.f() è il metodo f() di A, ovvero A.f() } } 35 1: Introduction Sottoclassi e ereditarietà /6 class A { int i = 1; int f() {return i;} } public class eredi2 extends A { int i; /* Questo campo nasconde il campo i di A */ int f() { /* Questo metodo ridefinisce il metodo f() di A */ i = super.i + 1; /* super.i è il campo i di A, ovvero A.I */ System.out.println(super.i); /* Stampa 1 */ System.out.println(super.f()); /* Stampa 1 */ System.out.println(i); /* Stampa 2 */ return super.f() + i; /* super.f() è il metodo f() di A, ovvero A.f() */ } public static void main(String args[]) { eredi2 myB; myB = new eredi2(); System.out.println(myB.i); /* Stampa 0 */ System.out.println(myB.f()); /* Stampa 3 */ } } 1: Introduction 36 Ricapitolando…. ! ! ! ! ! ! Method Overloading: definizione, nella stessa classe, di metodi/costruttori con lo stesso nome e firma diversa Field Shadowing: variabili della sottoclasse nascondono variabili della superclasse con lo stesso nome Method Overriding: ridefinizione nella sottoclasse di un metodo della superclasse con stesso nome, tipo restituito e lista dei parametri Attenzione a non confondere super() con super.f() I metodi static possono soltanto essere nascosti da metodi static con la stessa firma Metodi final: per definizione, un metodo final non può essere ridefinito 1: Introduction 37 Classi astratte Metodo astratto: prototipo, dichiarato con il modificatore abstract. Es.: public abstract void myMethod(String name); ! Classe astratta: ogni classe contenente almeno un metodo astratto ! ! Una classe astratta non può essere istanziata ! Per usare una classe astratta, è necessario definirne una sottoclasse che ne implementi tutti i metodi astratti ! Una classe astratta può contenere dichiarazioni di variabili e abstract class myClass { metodi non astratti int x; ..... public abstract void mymethod(int val); ......... } 1: Introduction 38 Interfacce ! Blocco di dichiarazioni di metodi, preceduta dalla parola chiave interface. Rende superflua l’ereditarietà multipla public interface myInterface { void firstMethod(String name); void secondMethod(); int thirdMethod(int val); } ! Una classe implementa l’interfaccia se ne implmenta tutti i metodi abstract class myClass implements myInterface { int x; public abstract void firstMethod(String name){ System.out.println(name); } /* Altri metodi, tra cui secondMethod() e thirdMethod() */ } 1: Introduction 39 Interfacce/2 public interface generalCircle { double area(); double circumference(); } ! Le classi Circle e myCircle implementano l’interfaccia ! Bisogna indicarlo esplicitamente: public class planeCircle extends Circle implements generalCircle { ..... } Esempio: Object implementa il metodo clone() ma non l’interfaccia Cloneable (nel senso che non lo indica esplicitamente) ! Si possono avere sottointerfacce 1: Introduction 40 Eccezioni ! ! Eccezione: “An event during program execution that prevents the program from continuing normally; generally, an error” (Tutorial) Java mette a disposizione meccanismi per la gestione delle eccezioni: µ µ Unità 1 Unità 2 try { ....... } catch{....} ....... ...throws Un meccanismo che permette a unità di programma di segnalare eccezioni (istruzione throw) Un costrutto che permette a unità di programma di gestire eccezioni segnalate da altre unità di programma (costrutto try-catch-finally) 1: Introduction 41 Eccezioni/2 ! ! Implementate come oggetti, istanze della classe (o di una sottoclasse di) java.lang.Throwable java.lang.Throwable ha due sottoclassi: µ µ ! java.lang.Error: errori generalmente irrecuperabili java.lang.Exception: errori meno gravi. Es.: tentativo di leggere un file inesistente (FileNotFoundException), lettura oltre gli indici iniziale o finale di un array (ArrayIndexOutOfBoundsException) Un metodo può lanciare un’eccezione con l’istruzione: throw <espressione>; il tipo di <espressione> deve essere quello dell’eccezione che si vuole lanciare ! Il costrutto try-catch identifica i blocchi di codice che possono generare eccezioni e permette di definire blocchi di codice per gestire diversi tipi di eccezione 1: Introduction 42 Eccezioni/3 ! ! ! ! Esistono numerose sottoclassi di Exception Unchecked exceptions: quelle che sono sottoclassi di java.lang.Error o java.lang.RuntimeException (ad esempio IllegalArgumentException). Non è obbligatorio gestirle Checked exceptions: le altre. Per esse occorre prevedere il blocco try-catch, altrimenti si ha errore di compilazione Vedremo molti esempi di eccezioni del secondo tipo public class myMathClass { public static double factorial(int x) { if(x<0) throw IllegalArgumentException(^x deve essere >= 0_); double fact; for(fact = 1.0; x > 1; fact *= x, x--); return fact; } } /*In un’altra classe...*/ ......... int y; ......... int fatt; try { fatt = myMathClass.factorial(y);} catch(IllegalArgumentException e) { System.out.println(^Argomento errato_); } \\\. 43 1: Introduction Eccezioni/4 ! Blocco catch: µ ! Si ha un blocco catch per ogni tipo di eccezione che viene gestito (non è detto che siano tutte le eccezioni possibili) Blocco finally: è opzionale e può servire a eseguire azioni che vanno comunque compiute e/o a gestire il caso in cui l’eccezione non appartenga ad alcuno dei tipi previsti nei blocchi catch try { \ (qui 1 contenuto del codice che pu1 lanciare un]eccezione) } catch(SomeException e1) { \ (codice che gestisce un]eccezione di tipo SomeException) } catch(AnotherException e2) { \ (codice che gestisce un]eccezione di tipo AnotherException) } finally { \ (codice che viene sempre eseguito, dopo essere usciti per qualsiasi motivo dal blocco try 1 tranne nel caso in cui venga invocato il metodo System.exit(), che interrompe l]esecuzione dell]interprete Java) } 1: Introduction 44 Eccezioni/5 Se l’esecuzione di <Istruzione 1> genera un’eccezione, nessuna delle istruzioni successive è eseguita ! Un blocco catch può non gestire direttamente un’eccezione, ma lanciarla a sua volta all’unità chiamante ! try { `<7#+8E(*4$%@a `<7#+8E(*4$%Ta ??????????????????????????????????? } catch(SomeException e1) { \ (codice che gestisce un]eccezione di tipo SomeException) } catch(AnotherException e2) { #P+*b%4$b%O4*#P$+NX5$)#(*4FH& 'D%#P+*b%$T&%-0%045P$%!$4$%D' } catch(Exception e3) { \ (simile alla clausola default del costrutto switch) } finally { \ (codice che viene sempre eseguito) } 1: Introduction 45 Eccezioni/6 Si possono definire nuove eccezioni come sottoclassi ! Sono di tipo checked se non sottoclassi di eccezioni unchecked ! Attenzione: un metodo che può lanciare un’ eccezione unchecked deve segnalarlo con la clausola throws ! class myMathException extends Exception { myMathException(String message) { /*COSTRUTTORE */ super(message); } } public class myMathClass { public static double factorial(int x) throws myMathException { if(x<0) throw new myMathException("x deve essere >= 0"); double fact; for(fact = 1.0; x > 1; fact *= x, x--); return fact; } public static void main(String args[]) throws myMathException { int x = -1; try { System.out.println(myMathClass.factorial(x)); } catch (myMathException e) { throw e; } } } 46 1: Introduction Ricapitolando…. ! Le eccezioni checked devono essere gestite ! Se un metodo può generare un’eccezione checked deve segnalarlo con la clausola throws ! Un blocco catch può limitarsi a rilanciare un’eccezione ! Se Exception2 è sottoclasse di Exception1 allora il blocco catch relativo a Exception1 cattura anche eccezioni di tipo Exception2 ! Si possono definire nuove eccezioni come sottoclassi di eccezioni già definite ! Se le nuove eccezioni non sono sottoclassi di java.lang.RuntimeException allora sono di tipo checked ! Molti metodi di classi predefinite possono lanciare eccezioni di vario tipo ! Utile nell’accesso alle risorse di sistema 1: Introduction 47