Università degli Studi di Modena e Reggio Emilia Facoltà di Ingegneria CORSO DI FONDAMENTI DI INFORMATICA C Linguaggio Java: Eccezioni Prof. Zambonelli, Ing. Cabri, Ing. Denti, Ing. Andrea Aime Zambonelli, Cabri, Denti, Aime - ECCEZIONI IN JAVA 1 ECCEZIONI Ogni programma può incontrare vari tipi di errore durante la sua vita. Questo accade in particolar modo quando il programma fa uso di risorse esterne, fornite dal sistema operativo, quali ad esempio: • file • stampanti • comunicazione fra programmi distinti, in remoto o in locale In una situazione “normale” nessuno di questi errori si scatena, ma il programma li deve gestire perché sono comunque situazioni possibili (la stampante è spenta, la rete non è disponibile, lo spazio su disco è terminato o non abbiamo i diritti per accedere ad un determinato file). La soluzione del C e di altri linguaggi procedurali è di fornire un valore di ritorno che indica la condizione di errore, o di impostare una variabile globale che può essere verificata. Verificare questi errori significa introdurre controlli (if… then..) per ogni operazione critica: il codice risulta rapidamente offuscato dalle routine di gestione errore. Inoltre, non vi è nessun obbligo di gestire questi errori. Java adotta un approccio totalmente differente, basato sul concetto di eccezione e di blocco controllato: • le operazioni critiche sono incluse entro un blocco controllato, senza verifiche di errore all’interno del blocco • se si verifica una eccezione, il controllo salta in un secondo blocco, dedicato alla gestione di una o più eccezioni. Zambonelli, Cabri, Denti, Aime - ECCEZIONI IN JAVA 2 Si dice che l’operazione critica ha sollevato (o lanciato) una eccezione e che il blocco di gestione l’ha catturata. Può accadere che alcune operazioni debbano essere svolte sia nel caso in cui l’eccezione venga sollevata, sia nel caso in cui l’eccezione non accada. Queste vengono svolte in un apposito blocco di chiusura, tipicamente usato per rilasciare risorse, ad esempio per chiudere file o canali di comunicazione. Il blocco finally è opzionale. try { // operazione critica che può sollevare eccez. } catch (XXXException ex) { // gestione dell’eccezione ex } catch (YYYException ey) { // gestione dell’eccezione ey } finally { // operazioni svolte sia che l’eccezione sia // sollevata che nel caso opposto } Se l’operazione può sollevare diversi tipi di eccezione (corrispondenti a diversi tipi di errore), possono essere previsti più blocchi catch di seguito allo stesso blocco try. Ogni blocco cattura l’eccezione dichiarata e le sue sottoclassi. Zambonelli, Cabri, Denti, Aime - ECCEZIONI IN JAVA 3 ESEMPIO Una tipica operazione “critica” è la lettura da input. In Java, il dispositivo di input standard è la variabile (static) System.in, di classe InputStream. Poiché InputStream fornisce solo un metodo read() che legge singoli byte, si usa incapsulare System.in in un oggetto dotato di maggiori funzionalità, BufferedReader, che fornisce anche un metodo readLine(): import java.io.*; class EsempioIn { public static void main(String args[]){ int a = 0, b = 0; BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); try { System.out.print("Primo valore: "); a = Integer.parseInt(in.readLine()); System.out.print("Secondo valore:"); b = Integer.parseInt(in.readLine()); } catch (IOException e) { System.out.println("Errore in input"); } System.out.println("La somma vale " + (a+b)); }} Qui, readLine() solleva una IOException in caso di errore in fase di input, mentre Integer.parseInt() solleva una NumberFormatException (non catturata) se la stringa restituita da readLine() non corrisponde alla sintassi di un numero intero. Zambonelli, Cabri, Denti, Aime - ECCEZIONI IN JAVA 4 COS’È UN’ECCEZIONE Una eccezione è un oggetto, istanza di java.lang.Throwable o di una sua sottoclasse. In particolare, vi sono tre sottoclassi notevoli • Error: sono errori fatali, irrecuperabili, che non possono in genere essere gestiti dal programma. Se uno di questi accade, la virtual machine semplicemente termina la sua esecuzione • Exception: eccezioni comuni, sottoposte alla regola “gestisci o rilancia”. • RuntimeException: particolare famiglia di eccezioni non sottoposta alla regola “gestisci o rilancia”. Sono eccezioni che non hanno bisogno di essere gestire, perché corrispondono in genere ad errori di programmazione (ad esempio, IndexOutOfBoundException, ClassCastException), non si dovrebbero verificare in un programma scritto correttamente. Poiché un’eccezione è un oggetto, può contenere dati o definire metodi (ad esempio getMessage(), o printStackTrace()). Un metodo entro cui si può generare un’eccezione deve gestire l’eccezione, con un costrutto try/catch, oppure dichiarare di Zambonelli, Cabri, Denti, Aime - ECCEZIONI IN JAVA 5 rilanciarla all’esterno del metodo stesso, con la clausola throws: public int readInteger(BufferedReader in) throws IOException, NumberFormatException { return Integer.parseInt(in.readLine()); } Una eccezione non catturata si propaga verso l’esterno, di blocco in blocco: se raggiunge il main, provoca l’aborto del programma. Zambonelli, Cabri, Denti, Aime - ECCEZIONI IN JAVA 6 DEFINIRE E GENERARE NUOVE ECCEZIONI Essendo un’eccezione un normale oggetto Java è possibile • definire nuovi tipi di eccezione definendo nuove classi • sollevare eccezioni dall’interno di propri metodi. Per definire un nuovo tipo di eccezione basta definire una nuova classe che estenda la classe Exception o una delle sue sottoclassi. Ad esempio: class NumberTooBigException extends IllegalArgumentException { public NumberTooBigException() { super(); } public NumberTooBigException(String s){super(s);} } Solitamente non è necessario definire particolari campi dati, in quanto l’informazione fondamentale (il tipo dell’eccezione) è già veicolata dalla classe stessa (e dal messaggio s). Per lanciare un’eccezione dall’interno di un metodo occorre creare l’oggetto eccezione, e poi “lanciarlo” con l’istruzione throw: public int readInteger(BufferedReader in) throws IOException, NumberFormatException, NumberTooBigException { int x = Integer.parseInt(in.readLine()); if (x>100) throw new NumberTooBigException(); return x; } • non confondere throw (che è un’istruzione che lancia un’eccezione) con la dichiarazione throws (usata nella dichiarazione di una classe) • la creazione dell’oggetto NumberTooBigException può avvenire - e spesso avviene - entro l’istruzione throw stessa. Zambonelli, Cabri, Denti, Aime - ECCEZIONI IN JAVA 7