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