Gestione delle eccezioni in Java



Documenti analoghi
Concetti Base Eccezioni Eccezioni e Metodi Gerarchia di Eccezioni. Java: Eccezioni. Damiano Macedonio

Gestione delle Eccezioni

Eccezioni ed asserzioni

Modulo 4: Ereditarietà, interfacce e clonazione

Tipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto:

La gestione dell input/output da tastiera La gestione dell input/output da file La gestione delle eccezioni

Programmazione a Oggetti Lezione 10. Ereditarieta

Visual Basic.NET La Gestione degli Errori di Federico BARBATI

Parola chiave extends

Main System Monitor Keyboard

Eccezioni 1 CASO: SENTIRE E GESTIRE UN ALLARME. Prof. Enrico Denti Università di Bologna A.A. 2012/ SITUAZIONI CRITICHE IL CONCETTO DI ECCEZIONE

Concetto di Funzione e Procedura METODI in Java

13. Chain of Responsibility

Oggetti Lezione 3. aspetti generali e definizione di classi I

Introduzione. Java. Composizione. Esempio -- composizione. G. Prencipe È qualcosa che abbiamo già visto varie volte

Ottava Esercitazione. introduzione ai thread java mutua esclusione

Java: Compilatore e Interprete

Operazioni di input/output. Prof. Francesco Accarino IIS Altiero Spinelli Via Leopardi 132 Sesto San Giovanni

Soluzione dell esercizio del 2 Febbraio 2004

Linguaggi Corso M-Z - Laurea in Ingegneria Informatica A.A Esercitazione. Programmazione Object Oriented in Java

Realizzazione di una classe con un associazione

Struttura di un programma Java

Siti web centrati sui dati Architettura MVC-2: i JavaBeans

Esercizi della lezione 5 di Java

Programmare in Java. Olga Scotti

Introduzione JDBC interfaccia java.sql driver caricare i driver

Progettazione : Design Pattern Creazionali

13 - Gestione della Memoria nella Programmazione Orientata agli Oggetti

La selezione binaria

Programmazione Java: Variabili membro, Metodi La parola chiave final

Architettura MVC-2: i JavaBeans

Tricks & Tips. [Access] Tutorial - ActiveX - Controllo Tree View. - Michele de Nittis - Versione: 1 Data Versione: venerdì 30 agosto 2002

Scrivere un programma in Java

3 - Variabili. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Appunti di Informatica 1

GESTIONE DEI PROCESSI

Esercizi su. Funzioni

Object Oriented Programming

Siamo così arrivati all aritmetica modulare, ma anche a individuare alcuni aspetti di come funziona l aritmetica del calcolatore come vedremo.

Manuale Utente Albo Pretorio GA

Uso di JUnit. Fondamenti di informatica Oggetti e Java. JUnit. Luca Cabibbo. ottobre 2012

Sviluppo Applicazioni Mobile Lezione 12 JDBC. Dr. Paolo Casoto, Ph.D

Programmazione Orientata agli Oggetti in Linguaggio Java

Gli array. Gli array. Gli array. Classi di memorizzazione per array. Inizializzazione esplicita degli array. Array e puntatori

Esercitazione n 4. Obiettivi

Libreria standard Java possiede un enorme libreria di classi standard organizzata in vari package che raccolgono le classi secondo un organizzazione

Università di Torino Facoltà di Scienze MFN Corso di Studi in Informatica. Programmazione I - corso B a.a prof.

Gestione Filtri. InfoBusiness 2.8 Gestione Filtri Pag. 1/ 11

Definizione di classi con array di oggetti

Luca Mari, Sistemi informativi applicati (reti di calcolatori) appunti delle lezioni. Architetture client/server: applicazioni server

Allocazione dinamica della memoria - riepilogo

Specifica i tipi di oggetti a creare, utilizzando un istanza prototipo, e crea nuove istanze tramite la copia di questo prototipo.

Fondamenti di Informatica 1. Prof. B.Buttarazzi A.A. 2010/2011

Invio SMS. DM Board ICS Invio SMS

Inizializzazione, Assegnamento e Distruzione di Classi

Java threads (2) Programmazione Concorrente

Java Virtual Machine

Funzioni in C. Violetta Lonati

Esercizio 1: trading on-line

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli

Programmazione Java Avanzata Concetti su Java

Test di unità con JUnit4

<?php include './include/page.php';

Algebra di Boole: Concetti di base. Fondamenti di Informatica - D. Talia - UNICAL 1. Fondamenti di Informatica

19. Introduzione al multi-threading

Gestione Risorse Umane Web

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica

Java:Struttura di Programma. Fabio Scanu a.s. 2014/2015

Sistemi Operativi MECCANISMI E POLITICHE DI PROTEZIONE. D. Talia - UNICAL. Sistemi Operativi 13.1

MECCANISMI E POLITICHE DI PROTEZIONE 13.1

Mobilità di Codice. Massimo Merro Programmazione di Rete 128 / 144

Introduzione alla programmazione Java. Dott. Ing. M. Banci, PhD

Approccio stratificato

Registri RMI. Massimo Merro Univ. Verona Programmazione di Rete 90 / 247

Eclipse. Avviare un progetto e compilare un semplice programma

Eredità in C++ Corso di Linguaggi di Programmazione ad Oggetti 1. a cura di Giancarlo Cherchi


Telematica II 17. Esercitazione/Laboratorio 6

JDBC. A. Bechini Accesso a DataD con Java

12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP)

Progettazione della componente applicativa

void funzioneprova() { int x=2; cout<<"dentro la funzione x="<<x<<endl; }

Il linguaggio C# Eventi ed eccezioni

4 3 4 = 4 x x x 10 0 aaa

Sistema operativo: Gestione della memoria

OSSIF WEB. Manuale query builder

Convertitori numerici in Excel

File Server Resource Manager (FSRM)

Indice generale. OOA Analisi Orientata agli Oggetti. Introduzione. Analisi

RISOLUTORE AUTOMATICO PER SUDOKU

Esercitazione 4 JDBC

Nascita di Java. Che cos e Java? Caratteristiche di Java. Java: linguaggio a oggetti

SOMMARIO... 3 INTRODUZIONE...

Basi di dati e Web (Moduli: Laboratorio e Siti Web centrati sui Dati) Prova scritta del 14 luglio 2008

Transcript:

Gestione delle eccezioni in Java - Introduzione al concetto di eccezioni E possibile definire un eccezione come un situazione imprevista che il flusso di un applicazione può incontrare. È possibile gestire un eccezione in Java, imparando ad utilizzare cinque semplici parole chiave: try, catch, finally, throw e throws. Sarà anche possibile creare eccezioni personalizzate e decidere non solo come, ma anche in quale parte del codice gestirle, grazie ad un meccanismo di propagazione estremamente potente. Questo concetto è implementato nella libreria Java mediante la classe Exception e le sue sottoclassi. Un esempio di eccezione che potrebbe verificarsi all interno di un programma è quella relativo ad un divisione tra due variabili numeriche nella quale la variabile divisore ha valore 0. Come è noto infatti, tale operazione non è fattibile. È invece possibile definire un errore come una situazione imprevista non dipendente da un errore commesso dallo sviluppatore. A differenza delle eccezioni quindi, gli errori non sono gestibili. Questo concetto è implementato nella libreria Java mediante la classe Error e le sue sottoclassi. Un esempio di errore che potrebbe causare un programma è quello relativo alla terminazione delle risorse di memoria. Ovviamente, questa condizione non è gestibile. - Gerarchie e categorizzazioni Nella libreria standard di Java, esiste una gerarchia di classi che mette in relazione, la classe Exception e la classe Error. Infatti, entrambe queste classi estendono la superclasse Throwable. La seguente figura mostra tale gerarchia: N.B. : un ulteriore categorizzazione delle eccezioni, è data dalla divisione delle eccezioni in checked ed unchecked exception. Ci si riferisce alle RuntimeException (e le sue sottoclassi) come unchecked exception. Tutte le altre eccezioni (ovvero tutte quelle che non derivano da RuntimeException), vengono dette checked exception. Se si utilizza un metodo che lancia una checked exception senza gestirla da qualche parte, la compilazione non andrà a buon fine. Da qui il termine checked exception (in italiano eccezioni controllate). Come abbiamo già detto, non bisognerà fare confusione tra il concetto di errore (problema che un programma non può risolvere) e di eccezione (problema non critico gestibile). Il fatto che sia la classe Exception sia la classe Error, estendano una classe che si chiama lanciabile (Throwable), è dovuto al meccanismo con cui la Java Virtual Machine reagisce quando si imbatte in una eccezione-errore. Infatti, se il nostro programma genera un eccezione durante il runtime, la JVM istanzia un oggetto dalla classe eccezione relativa al problema, e lancia l eccezione appena istanziata

(tramite la parola chiave throw). Se il nostro codice non cattura (tramite la parola chiave catch) l eccezione, il gestore automatico della JVM interromperà il programma generando in output informazioni dettagliate su ciò che è accaduto. Per esempio, supponiamo che durante l esecuzione un programma provi ad eseguire una divisione per zero. La JVM istanzierà un oggetto di tipo ArithmeticException (inizializzandolo opportunamente) e lo lancerà. In pratica è come se la JVM eseguisse le seguenti righe di codice: ArithmeticException exc = new ArithmeticException(); throw exc; Tutto avviene dietro le quinte, e sarà trasparente al lettore. - Meccanismo per la gestione delle eccezioni Come già asserito in precedenza, lo sviluppatore ha a disposizione alcune parole chiave per gestire le eccezioni: try, catch, finally, throw e throws. Se bisogna sviluppare una parte di codice che potenzialmente può scatenare un eccezione è possibile circondarlo con un blocco try seguito da uno o più blocchi catch. Per esempio: public class Ecc1 { public static void main(string args[]) { Questa classe può essere compilata senza problemi, ma genererà un eccezione durante la sua esecuzione, dovuto all impossibilità di eseguire una divisione per zero. In tal caso, la JVM dopo aver interrotto il programma produrrà il seguente output: Exception in thread "main" java.lang.arithmeticexception: / by zero at Ecc1.main(Ecc1.java:6) Un messaggio di sicuro molto esplicativo, infatti sono stati evidenziati: - il tipo di eccezione (java.lang.arithmeticexception) - un messaggio descrittivo (/ by zero) - il metodo in cui è stata lanciata l eccezione (at Ecc1.main) - il file in cui è stata lanciata l eccezione (Ecc1.java) - la riga in cui è stata lanciata l eccezione (:6)

L unico problema è che il programma è terminato prematuramente. Utilizzando le parole chiave try e catch sarà possibile gestire l eccezione in maniera personalizzata: public class Ecc2 { public static void main(string args[]) { catch (ArithmeticException exc) { System.out.println("Divisione per zero..."); Quando la JVM eseguirà tale codice incontrerà la divisione per zero della prima riga del blocco try, lancerà l eccezione ArithmeticException che verrà catturata nel blocco catch seguente. Quindi non sarà eseguita la riga che doveva stampare la variabile c, bensì la stringa Divisione per zero..., con la quale abbiamo gestito l eccezione, ed abbiamo permesso al nostro programma di terminare in maniera naturale. Come il lettore avrà sicuramente notato, la sintassi dei blocchi try catch è piuttosto strana, ma presto ci si fa l abitudine, perché è presente più volte praticamente in tutti i programmi Java. In particolare il blocco catch deve dichiarare un parametro (come se fosse un metodo) del tipo dell eccezione che deve essere catturata. Nell esempio precedente il reference exc, puntava proprio all eccezione che la JVM aveva istanziato e lanciato. Infatti tramite esso, è possibile reperire informazioni proprio sull eccezione stessa. Il modo più utilizzato e completo per ottenere informazioni su ciò che è successo, è invocare il metodo printstacktrace() sull eccezione stessa: catch (ArithmeticException exc) { Il metodo printstacktrace() produrrà in output i messaggi informativi (di cui sopra) che il programma avrebbe prodotto se l eccezione non fosse stata gestita, ma senza interrompere il programma stesso.

È ovviamente fondamentale che si dichiari, tramite il blocco catch, un eccezione del tipo giusto. Per esempio, il seguente frammento di codice: catch (NullPointerException exc) { produrrebbe un eccezione non gestita, e, quindi, un immediata terminazione del programma. Infatti, il blocco try non ha mai lanciato una NullPointerException, ma una ArithmeticException. Come per i metodi, anche per i blocchi catch i parametri possono essere polimorfi. Per esempio, il seguente frammento di codice: catch (Exception exc) { contiene un blocco catch che gestirebbe qualsiasi tipo di eccezione, essendo Exception, la superclasse da cui discende ogni altra eccezione. Il reference exc, è in questo esempio, un parametro polimorfo. È anche possibile far seguire ad un blocco try, più blocchi catch, come nel seguente esempio: catch (ArithmeticException exc) { System.out.println("Divisione per zero..."); catch (NullPointerException exc) { System.out.println("Reference nullo...");

catch (Exception exc) { In questo modo il nostro programma risulterebbe più robusto, e gestirebbe diversi tipi di eccezioni. Male che vada (ovvero il blocco try lanci un eccezione non prevista), l ultimo blocco catch gestirà il problema. N.B. : è ovviamente fondamentale l ordine dei blocchi catch. Se avessimo: catch (Exception exc) { catch (ArithmeticException exc) { System.out.println("Divisione per zero..."); catch (NullPointerException exc) { System.out.println("Reference nullo..."); allora gli ultimi due catch sarebbero superflui e il compilatore segnalerebbe l errore nel seguente modo: C:\Ecc2.java:12: exception java.lang.arithmeticexception has already been caught catch (ArithmeticException exc) { ^ C:\Ecc2.java:15: exception java.lang.nullpointerexception has already been caught catch (NullPointerException exc) { ^ 2 errors È anche possibile far seguire ad un blocco try, oltre a blocchi catch, un altro blocco definito dalla parola chiave finally, per esempio: public class Ecc4 { public static void main(string args[]) {

catch (ArithmeticException exc) { System.out.println("Divisione per zero..."); catch (Exception exc) { finally { System.out.println("Tentativo di operazione"); Ciò che è definito in un blocco finally, viene eseguito in qualsiasi caso, sia se viene lanciata l eccezione, sia se non viene lanciata. Per esempio, è possibile utilizzare un blocco finally quando esistono operazioni critiche che devono essere eseguite in qualsiasi caso. L output del precedente programma è: Divisione per zero... tentativo di operazione Se invece la variabile b fosse settata a 2 piuttosto cha a 0, allora l output sarebbe: 5 tentativo di operazione Un classico esempio (più significativo del precedente) in cui la parola finally è spesso utilizzata è il seguente: public void insertindb() { cmd.executeupdate( INSERT INTO ) catch (SQLException exc) { finally { connection.close(); Il metodo precedente, tenta di eseguire una INSERT in un database, tramite le interfacce JDBC offerte dal package java.sql. Nell esempio cmd è un oggetto Statement e connection è un oggetto di tipo Connection. Il comando executeupdate() specifica come parametro una stringa con codice SQL per inserire un certo record in una certa tabella di un certo database. Se ci sono problemi (per esempio sintassi SQL scorretta, chiave primaria già presente, etc ) la JVM lancerà una SQLException, che verrà catturata nel relativo blocco catch. In ogni caso, dopo il tentativo di inserimento, la connessione al database deve essere chiusa. (per una breve introduzione su JDBC, rimandiamo il lettore all indirizzo,

http://www.claudiodesio.com/java/jdbc.htm). N.B. : è possibile anche far seguire ad un blocco try, direttamente un blocco finally. Quest ultimo verrà eseguito sicuramente dopo l esecuzione del blocco try, sia se l eccezione viene lanciata, sia se non viene lanciata. Comunque, se l eccezione venisse lanciata, non essendo gestita con un blocco catch, il programma terminerebbe anormalmente. N.B. : A questo punto in molti si potrebbero chiedere il perché gestire le eccezioni con blocchi try catch, piuttosto che utilizzare dei semplici if. La risposta sarà implicitamente data nei prossimi paragrafi. - Eccezioni personalizzate e propagazione dell'eccezione Ci sono alcune tipologie di eccezioni che sono più frequenti e quindi più conosciute dagli sviluppatori Java. Si tratta di: NullPointerException : probabilmente la più frequente tra le eccezioni. Viene lanciata dalla JVM, quando per esempio viene chiamato un metodo su di un reference che invece punta a null. ArrayIndexOutOfBoundsException : questa eccezione viene ovviamente lanciata quando si prova ad accedere ad un indice di un array troppo alto. ClassCastException : eccezione particolarmente insidiosa. Viene lanciata al runtime quando si prova ad effettuare un cast ad un tipo di classe sbagliato. Queste eccezioni appartengono tutte al package java.lang. Inoltre, se si utilizzano altri package come java.io, bisognerà gestire spesso le eccezioni come IOException e le sue sottoclassi (FileNotFoundException, EOFException, etc ). Stesso discorso con la libreria java.sql e l eccezione SQLException, il package java.net e la ConnectException e così via. Lo sviluppatore imparerà con l esperienza come gestire tutte queste eccezioni. È però altrettanto probabile che qualche volta occorra definire nuovi tipi di eccezioni. Infatti, per un particolare programma. potrebbe essere una eccezione anche una divisione per 5. Più verosimilmente, un programma che deve gestire in maniera automatica le prenotazioni per un teatro, potrebbe voler lanciare un eccezione nel momento in cui si tenti di prenotare un posto non più disponibile. In tal caso la soluzione è estendere la classe Exception, ed eventualmente aggiungere membri e fare override di metodi come tostring(). Segue un esempio: public class PrenotazioneException extends Exception { public PrenotazioneException() { // Il costruttore di Exception chiamato inizializza la // variabile privata message super( Problema con la prenotazione ); public String tostring() { return getmessage() + : posti esauriti! ;

La nostra eccezione, contiene informazioni sul problema, e rappresenta una astrazione corretta. Tuttavia la JVM, non può lanciare automaticamente una PrenotazioneException nel caso si tenti di prenotare quando non ci sono più posti disponibile. La JVM infatti, sa quando lanciare una ArithmeticException ma non sa quando lanciare una PrenotazioneException. In tal caso sarà compito dello sviluppatore lanciare l eccezione. Esiste infatti la parola chiave throw (in inglese lancia ), che permette il lancio di un eccezione tramite la seguente sintassi: PrenotazioneException exc = new PrenotazioneException(); throw exc; o equivalentemente (dato che il reference exc poi non sarebbe più utilizzabile): throw new PrenotazioneException(); Ovviamente il lancio dell eccezione dovrebbe seguire un controllo condizionale come il seguente: if (postidisponibili == 0) { throw new PrenotazioneException(); Il codice precedente ovviamente farebbe terminare prematuramente il programma a meno di gestire l eccezione come segue: //controllo sulla disponibilità dei posti if (postidisponibili == 0) { //lancio dell eccezione throw new PrenotazioneException(); //istruzione eseguita // se non viene lanciata l eccezione postidisponibili--; catch (PrenotazioneException exc){ System.out.println(exc.toString()); Il lettore avrà sicuramente notato che il codice precedente non rappresenta un buon esempio di gestione dell eccezione: dovendo utilizzare la condizione if, sembra infatti superfluo l utilizzo dell eccezione. In effetti è così! Ma ci deve essere una ragione per la quale esiste la possibilità di creare eccezioni personalizzate e di poterle lanciare. Questa ragione è la propagazione dell eccezione per i metodi chiamanti. La potenza della gestione delle eccezioni è dovuta essenzialemente a questo meccanismo di propagazione. Per comprenderlo bene, affidiamoci coma la solito ad un esempio. Supponiamo di avere la seguente classe: public class Botteghino { private int postidisponibili;

public Botteghino() { postidisponibili = 100; public void prenota() { //controllo sulla disponibilità dei posti if (postidisponibili == 0) { //lancio dell eccezione throw new PrenotazioneException(); //metodo che realizza la prenotazione // se non viene lanciata l eccezione postidisponibili--; catch (PrenotazioneException exc){ System.out.println(exc.toString()); La classe Botteghino astrae in maniera semplicistica, un botteghino virtuale che permette di prenotare i posti in un teatro. Ora consideriamo la seguente classe eseguibile (con metodo main) che utilizza la classe Botteghino: public class GestorePrenotazioni { public static void main(string [] args) { Botteghino botteghino = new Botteghino(); for (int i = 0; i < 101; ++i){ botteghino.prenota(); System.out.println( Prenotato posto n + i); Per una classe del genere, il fatto che l eccezione sia gestita all interno della classe Botteghino, rappresenta un problema. Infatti l output del programma sarà: Prenotato posto n 1 Prenotato posto n 2... Prenotato posto n 99 Prenotato posto n 100 Problema con la prenotazione: posti esauriti! Prenotato posto n 101 che ovviamente contiene una contraddizione. Gestire eccezioni è sempre una operazione da fare, ma non sempre bisogna gestire eccezioni laddove si presentano. In questo caso, l ideale sarebbe gestire l eccezione nella classe GestorePrenotazioni, piuttosto

che nella classe Botteghino: public class GestorePrenotazioni { public static void main(string [] args) { Botteghino botteghino = new Botteghino(); for (int i = 1; i <= 101; ++i){ botteghino.prenota(); System.out.println( Prenotato posto n + i); catch (PrelievoException exc) { System.out.println(exc.toString()); Tutto ciò è fattibile grazie al meccanismo di propagazione dell eccezione di Java. Per compilare la classe Botteghino però, non basta rimuovere il blocco try catch dal metodo prenota, ma bisogna anche utilizzare la parola chiave throws nel seguente modo: public void prenota() throws PrelievoException { //controllo sulla disponibilità dei posti if (postidisponibili == 0) { //lancio dell eccezione throw new PrenotazioneException(); //metodo che realizza la prenotazione // se non viene lanciata l eccezione postidisponibili--; In questo modo otteremo il seguente desiderabile output: Prenotato posto n 1 Prenotato posto n 2... Prenotato posto n 99 Prenotato posto n 100 Problema con la prenotazione: posti esauriti! Se non utilizzassimo la clausola throws nella dichiarazione del metodo, il compilatore non compilerebbe il codice precedente. Infatti, segnalerebbe che il metodo prenota potrebbe lanciare l eccezione PrelievoException (che è evidente al compilatore per la parola chiave throw), e che questa, non viene gestita. In particolare il messaggio di errore restituito sarebbe simile al seguente: GestorePrenotazioni2.java:5: unreported exception

PrenotazioneException; must be caught or declared to be thrown N.B. : Questo messaggio è una ulteriore prova delle caratteristiche di robustezza di Java. Con la clausola throws nella dichiarazione del metodo, in pratica è come se avvertissimo il compilatore che siamo consapevoli che il metodo possa lanciare al runtime la PrelievoException, e di non preoccuparsi, perché gestiremo in un altra parte del codice l eccezione. N.B. : Se un metodo chiamante vuole utilizzare un altro metodo dachiamare che dichiara con una clausola throws il possibile lancio di un certo tipo di eccezione, allora, il metodo chiamante, o deve gestire l eccezione con un blocco try catch che include la chiamata al metodo dachiamare, o deve dichiarare anch esso una clausola throws alla stessa eccezione. Ad esempio, ciò vale per il metodo main della classe GestorePrenotazioni. N.B. : Molti metodi della libreria standard sono dichiarati con clausola throws a qualche eccezione. Per esempio molti metodi delle classi del package java.io, dichiarano clausole throws alla IOException (eccezione di input - output). Appare ancora più chiaro ora la categorizzazione tra eccezioni checked ed unchecked: le checked exception devono essere per forza gestite per poter compilare, le uncheked no, dato che si presentano solo al runtime. N.B. : E possibile dichiarare nella clausola throws anche più di una eccezione, separando le varie tipologie con virgole, come nel seguente esempio: public void prenota() throws PrelievoException, NullPointerException {... - Precisazione sull override: Quando si fa override di un metodo, non è possibile specificare clausole throws ad eccezioni che il metodo base non ha nella propria clausola throws. È comunque possibile da parte del metodo che fa override, dichiarare una clausola throws ad eccezioni che sono sottotipi di eccezioni che il metodo base, ha nella sua clausola throws. Per esempio: public class ClasseBase { public void metodo() throws java.io.ioexception { class SottoClasseCorretta1 extends ClasseBase { public void metodo() throws java.io.ioexception { class SottoClasseCorretta2 extends ClasseBase { public void metodo() throws java.io.filenotfoundexception {

class SottoClasseCorretta3 extends ClasseBase { public void metodo() { class SottoClasseScorretta extends ClasseBase { public void metodo() throws java.sql.sqlexception { La classe ClasseBase ha un metodo che dichiara nella sua clausola throws una IOException. La classe SottoClasseCorretta1 fa override del metodo e dichiara la stessa IOException nella sua clausola throws. La classe SottoClasseCorretta2 fa override del metodo e dichiara una FileNotFoundException, che è sottoclasse di IOException nella sua clausola throws. La classe SottoClasseCorretta3 fa override del metodo e non dichiara clausole throws. Infine la classe SottoClasseScorretta, fa override del metodo e dichiara una SQLException nella sua clausola throws, e ciò è illegale.