Esercizi
- Home
- Esercizi Capitolo 8
Capitolo 8
Eccezioni ed asserzioni
La gestione delle eccezioni è un argomento fondamentale, è molto importante imparare ogni dettaglio
dell'argomento (non sono molti in fondo). Le asserzioni sono molto meno usate, ma potrebbero essere
usate con profitto.
Di seguito trovate gli esercizi del capitolo.
Per ogni esercizio, cliccando sulla traccia potete vedere la relativa soluzione.
Gli esercizi caratterizzati dall'icona sono
considerati i più complessi relativamente agli argomenti trattati.
Se preferite lavorare offline, è possibile scaricare tutti gli esercizi e le relative
soluzioni in formato PDF nella sezione download.
-
Esercizio 8.a) Gestione delle eccezioni e degli errori, Vero o Falso:
1. Ogni eccezione che estende una
ArithmeticException
è una unchecked exception.
2. UnError
si differenzia da unaException
perché non può essere lanciato; infatti non estende la classeThrowable
.
3. Il seguente frammento di codice:produrrà il seguente output:int a = 10; int b = 0; try { int c = a/b; System.out.println(c); } catch (ArithmeticException exc) { System.out.println("Divisione per zero..."); } catch (NullPointerException exc) { System.out.println("Reference nullo..."); } catch (Exception exc) { System.out.println("Eccezione generica..."); } finally { System.out.println("Finally!"); }
4. Il seguente frammento di codice:Divisione per zero... Eccezione generica... Finally!
produrrà un'eccezione al runtime.int a = 10; int b = 0; try { int c = a/b; System.out.println(c); } catch (Exception exc) { System.out.println("Eccezione generica..."); } catch (ArithmeticException exc) { System.out.println("Divisione per zero..."); } catch (NullPointerException exc) { System.out.println("Reference nullo..."); } finally { System.out.println("Finally!"); }
5. La parola chiave
throw
permette di lanciare "a mano" solo le sottoclassi diException
che crea il programmatore.
6. La parola chiavethrow
consente di lanciare "a mano" solo le sottoclassi diException
.
7. Se un metodo fa uso della parola chiavethrow
, affinché la compilazione abbia buon esito nello stesso metodo deve essere gestita l'eccezione che si vuole lanciare, o il metodo stesso deve utilizzare una clausolathrows
.
8. Non è possibile estendere la classeError
.
9. Se un metodom2
fa override di un altro metodom2
posto nella superclasse, non potrà dichiarare con la clausolathrows
eccezioni nuove che non siano sottoclassi rispetto a quelle che dichiara il metodom2
.
10. Dalla versione 1.4 di Java è possibile "includere" in un'eccezione un'altra eccezione.
Soluzione
1. Vero, perché
ArithmeticException
è sottoclasse diRuntimeException
.
2. Falso.
3. Falso, produrrà il seguente output:
4. Falso, produrrà un errore in compilazione (l'ordine dei blocchiDivisione per zero... Finally!
catch
non è regolare).
5. Falso.
6. Falso, solo le sottoclassi diThrowable
.
7. Vero.
8. Falso.
9. Vero.
10. Vero. -
Esercizio 8.b) Gestione delle asserzioni, Vero o Falso:
1. Se in un'applicazione un'asserzione non viene verificata, si deve parlare di bug.
2. Un'asserzione che non viene verificata provoca il lancio da parte della JVM di unAssertionError
.
3. Le precondizioni servono per testare la correttezza dei parametri di metodi pubblici.
4. È sconsigliato l'utilizzo di asserzioni laddove si vuole testare la correttezza di dati inseriti da un utente.
5. Una postcondizione serve per verificare che al termine di un metodo sia verificata un'asserzione.
6. Un'invariante interna permette di testare la correttezza dei flussi all'interno dei metodi.
7. Un'invariante di classe è una particolare invariante interna che deve essere verificata per tutte le istanze di una certa classe, in ogni momento del loro ciclo di vita, tranne che durante l'esecuzione di alcuni metodi.
8. Un'invariante sul flusso di esecuzione, è solitamente un'asserzione con una sintassi del tipo:
assert false;
9. Non è in alcun modo possibile compilare un programma che fa uso di asserzioni con il JDK 1.3.
10. Non è in alcun modo possibile eseguire un programma che fa uso di asserzioni con il JDK 1.3.
Soluzione
1. Vero.
2. Vero.
3. Falso.
4. Vero.
5. Vero.
6. Vero.
7. Vero.
8. Vero.
9. Vero.
10. Vero. -
Esercizio 8.c)
Consideriamo le classi create negli esercizi del capitolo 7:
File
,FileSorgente
,Editor
,IDE
eJavaIDE
. Consideriamo inoltre il metodoaggiungiTesto(String)
della classeFileSorgente
che abbiamo creato nell'esercizio 7.f, che avevamo codificato nel seguente modo:
public void aggiungiTesto(String testo) { if (contenuto != null && testo != null) { contenuto += testo; } }
Il controllo della clausola
if
si può sicuramente migliorare. Cosa usereste in questo caso, asserzioni o eccezioni?
Soluzione
Come abbiamo visto nell'approfondimento 8.3, non dovremmo mai usare le asserzioni per testare i parametri di un metodo pubblico. Quindi indubbiamente è più corretto usare la gestione delle eccezioni.
-
Esercizio 8.d)
(ALLARME SPOILER: le prossime righe rivelano la soluzione del precedente esercizio)
Dopo aver letto la soluzione dell'esercizio precedente, usare le parole chiave
throw
ed eventualmentethrows
per gestire eventuali eccezioni nel metodoaggiungiTesto(String)
citato nell'esercizio precedente.
Soluzione
Una possibile implementazione potrebbe essere la seguente:
public void aggiungiTesto(String testo) throws RuntimeException { if (contenuto == null) { contenuto = ""; } if (testo == null) { throw new RuntimeException("testo = null"); } contenuto += testo; }
Si noti che abbiamo rilanciato unaRuntimeException
, ma avremmo potuto rilanciare una qualsiasi altra eccezione (per esempioException
stessa). Inoltre la clausolathrows
accanto alla dichiarazione del metodo non è tecnicamente obbligatoria ma consigliabile. -
Esercizio 8.e)
Consideriamo ora il metodo
aggiungiTesto(String, int)
che abbiamo creato nell'esercizio 7.g e che avevamo codificato nel seguente modo:
public void aggiungiTesto(String testo, int posizione) { final int length = contenuto.length(); if (contenuto != null && testo != null && posizione > 0 && posizione < length) { contenuto = contenuto.substring(0, posizione) + testo + contenuto.substring(posizione); } }
Gestire un'eccezione (o più eccezioni) tramite le parole chiave
try
-catch
, e se possibile anchefinally
.
Soluzione
Il listato potrebbe essere simile al seguente:
public void aggiungiTesto(String testo, int posizione) { try { if (testo != null) { contenuto = contenuto.substring(0, posizione) + testo + contenuto.substring(posizione); } } catch (NullPointerException exc) { System.out.println("Il contenuto è null : " + exc.getMessage()); contenuto = "" + testo; } catch (StringIndexOutOfBoundsException exc) { System.out.println("L'indice " + posizione + " è invalido : " + exc.getMessage()); contenuto = (posizione < 0 ? testo + contenuto : contenuto + testo); } }
In questo esempio abbiamo solo controllato se il testo da aggiungere ènull
, in tal caso nessuna operazione viene eseguita. Poi abbiamo gestito laNullPointerException
che si presenterebbe nel casocontenuto
valganull
. Nella clausolacatch
abbiamo stampato un messaggio significativo e mantenuto la coerenza con il metodo precedentemente presentato.
Abbiamo anche gestito unaStringIndexOutOfBoundsException
che scatterebbe se la posizione specificata contenesse un numero negativo o maggiore della dimensione del contenuto del file. Anche in questo caso nella clausolacatch
abbiamo dapprima stampato un messaggio significativo, e poi "accomodato" la situazione. In particolare abbiamo fatto in modo che (sfruttando anche un operatore ternario), se la variabileposizione
è specificata con un valore negativo, allora la variabiletesto
viene messa all'inizio prima della variabilecontenuto
(come se fosse stata specificata la posizione 0). Se invece viene impostata con un valore superiore all'ultimo indice disponibile per il contenuto, allora la variabiletesto
viene aggiunta alla fine del contenuto. Infine, per quanto riguarda ilfinally
, l'impostazione della nostra soluzione non ne richiede l'uso. -
Esercizio 8.f)
Dopo aver svolto l'esercizio precedente, creare una classe di test
TestFileSorgente
per verificare che la gestione delle eccezioni funzioni correttamente.
Soluzione
Il listato della classe
TestFileSorgente
potrebbe essere il seguente:
public class TestFileSorgente { public static void main(String args[]) { FileSorgente fileSorgente = new FileSorgente("Test.java", TipoFile.JAVA, "public class MyClass {\n\r"); System.out.println(fileSorgente.getContenuto()); // Test aggiungiTesto(String) corretto fileSorgente.aggiungiTesto("}"); System.out.println(fileSorgente.getContenuto()); // Test aggiungiTesto(String,int) corretto fileSorgente.aggiungiTesto("//Test aggiunta testo\n\r", 23); System.out.println(fileSorgente.getContenuto()); // Test aggiungiTesto(String,int) scorretto fileSorgente.aggiungiTesto("//Test aggiunta testo\n\r", -1); System.out.println(fileSorgente.getContenuto()); // Test aggiungiTesto(String,int) scorretto fileSorgente.aggiungiTesto("//Test aggiunta testo\n\r", 100); System.out.println(fileSorgente.getContenuto()); FileSorgente fileSorgenteVuoto = new FileSorgente("FileVuoto.c", TipoFile.C); fileSorgenteVuoto.aggiungiTesto("//Test aggiunta testo\n\r", 3); System.out.println(fileSorgenteVuoto.getContenuto()); FileSorgente fileSorgenteVuoto2 = new FileSorgente("FileVuoto2.cpp", TipoFile.C_PLUS_PLUS); fileSorgenteVuoto2.aggiungiTesto("//Test aggiunta testo\n\r"); } }
-
Esercizio 8.g)
Consideriamo i sorgenti creati con gli esercizi realizzati per il capitolo 5. Creare delle eccezioni personalizzate per gestire le situazioni impreviste. In particolare creare un'eccezione che scatti nel costruttore della classe
PortaMonete
quando vengono specificate troppe monete, chiamiamolaPortaMonetePienoException
. Gestire l'eccezione direttamente nel costruttore istanziando comunque l'oggetto con un numero limitato di elementi (ovvero senza cambiare il comportamento già definito nell'esercizio del capitolo 5). Gestire anche laNullPointerException
(quale istruzione potrebbe generare tale eccezione?).
Soluzione
Il nuovo listato della classe
PortaMonetePienoException
potrebbe essere il seguente:
public class PortaMonetePienoException extends Exception { public PortaMonetePienoException(String message) { super(message); } }
Il listato del costruttore della classePortaMonete
, con i nuovi requisiti potrebbe essere trasformato nel seguente modo:
public PortaMonete(int... valori) { try { int numeroMonete = valori.length; for (int i = 0; i < numeroMonete; i++) { if (i >= 10) { throw new PortaMonetePienoException ( "Sono state inserite solo le prime 10 monete!"); } monete[i] = new Moneta(valori[i]); } } catch (PortaMonetePienoException | NullPointerException exc) { System.out.println(exc.getMessage()); } }
Si noti che passandonull
come parametro al costruttore, potremmo generare unaNullPointerException
quando viene richiesta la variabilelength
sul parametrovalori
(che varrebbe appuntonull
). Con un multi-catch
abbiamo garantito il funzionamento del costruttore senza che il programma si interrompa, stampando il messaggio del problema che si è presentato. Tuttavia non è corretto in questo caso gestire allo stesso modo questi due tipi di eccezione, in quanto nel caso dellaNullPointerException
il messaggio stampato sarà semplicemente:
null
che è poco esplicativo.
Sarebbe meglio gestire le due eccezioni in questo modo:
public PortaMonete(int... valori) { try { int numeroMonete = valori.length; for (int i = 0; i < numeroMonete; i++) { if (i >= 10) { throw new PortaMonetePienoException ( "Sono state inserite solo le prime 10 monete!"); } monete[i] = new Moneta(valori[i]); } // } catch (PortaMonetePienoException | NullPointerException exc) { } catch (PortaMonetePienoException exc) { System.out.println(exc.getMessage()); } catch (NullPointerException exc) { System.out.println("Il portamonete è stato creato vuoto"); } }
-
Esercizio 8.h)
Consideriamo i sorgenti creati con gli esercizi realizzati per il capitolo 5. Usare la gestione delle eccezioni personalizzate per gestire le situazioni impreviste. In particolare usare l'eccezione
PortaMonetePienoException
affinché scatti nel metodoaggiungi
che avevamo definito nel modo seguente:
public void aggiungi(Moneta moneta) { System.out.println("Proviamo ad aggiungere una " + moneta.getDescrizione()); int indiceLibero = primoIndiceLibero(); if (indiceLibero == -1) { System.out.println("Portamonete pieno! La moneta " + moneta.getDescrizione() + " non è stata aggiunta..."); } else { monete[indiceLibero] = moneta; System.out.println("E' stata aggiunta una " + moneta.getDescrizione()); } }
Fare in modo che l'eccezione
PortaMonetePienoException
sia lanciata opportunamente. Gestire anche eventuali altre eccezioni.
Soluzione
Il listato del metodo
aggiungi
della classePortaMonete
con i nuovi requisiti, potrebbe essere trasformato nel seguente modo:
public void aggiungi(Moneta moneta) throws PortaMonetePienoException { try { System.out.println("Proviamo ad aggiungere una " + moneta.getDescrizione()); } catch (NullPointerException exc) { throw new NullPointerException("La moneta passata era null"); } int indiceLibero = primoIndiceLibero(); if (indiceLibero == -1) { throw new PortaMonetePienoException("Portamonete pieno! La moneta " + moneta.getDescrizione() + " non è stata aggiunta..."); } else { monete[indiceLibero] = moneta; System.out.println("E' stata aggiunta una " + moneta.getDescrizione()); } }
Si noti che abbiamo gestito anche laNullPointerException
catturandola e rilanciandola con un messaggio migliore del "null
". Anche in questo caso l'eccezione si verificherebbe nel caso il parametro passato fossenull
, non appena fosse chiamato il metodogetDescrizione
sull'oggettomoneta
(che varrebbenull
). -
Esercizio 8.i)
Consideriamo i sorgenti creati con gli esercizi realizzati per il capitolo 5. Creare delle eccezioni personalizzate per gestire le situazioni impreviste. In particolare usare l'eccezione
MonetaNonTrovataException
affinché scatti nel metodopreleva
che avevamo definito nel modo seguente:
public Moneta preleva(Moneta moneta) { System.out.println("Proviamo a prelevare una " + moneta.getDescrizione()); Moneta monetaTrovata = null; int indiceMonetaTrovata = indiceMonetaTrovata(moneta); if (indiceMonetaTrovata == -1) { System.out.println("Moneta non trovata!"); } else { monetaTrovata = moneta; monete[indiceMonetaTrovata] = null; System.out.println("Una " + moneta.getDescrizione() + " prelevata"); } return monetaTrovata; }
Fare in modo che l'eccezione
MonetaNonTrovataException
sia lanciata opportunamente. Gestire anche eventuali altre eccezioni.
Soluzione
L'eccezione richiesta potrebbe essere la seguente:
public class MonetaNonTrovataException extends Exception { public MonetaNonTrovataException(String message) { super(message); } }
Il listato del metodopreleva
della classePortaMonete
, con i nuovi requisiti, potrebbe essere trasformato nel seguente modo:
public Moneta preleva(Moneta moneta) throws MonetaNonTrovataException { try { System.out.println("Proviamo a prelevare una " + moneta.getDescrizione()); } catch (NullPointerException exc) { throw new MonetaNullException(); } Moneta monetaTrovata = null; int indiceMonetaTrovata = indiceMonetaTrovata(moneta); if (indiceMonetaTrovata == -1) { throw new MonetaNonTrovataException("Moneta non trovata!"); } else { monetaTrovata = moneta; monete[indiceMonetaTrovata] = null; System.out.println("Una " + moneta.getDescrizione() + " prelevata"); } return monetaTrovata; }
Si noti che abbiamo gestito anche laNullPointerException
catturandola e rilanciandola con un messaggio migliore del "null
". Anche in questo caso l'eccezione si verificherebbe nel caso il parametro passato fossenull
, non appena viene chiamato il metodogetDescrizione
sull'oggettomoneta
(che varrebbenull
). Possiamo migliorare questo meccanismo creando un'altra eccezione personalizzata:
public class MonetaNullException extends RuntimeException { public MonetaNullException() { super("La moneta passata era null"); } }
AMonetaNullException
gli abbiamo fatto estendereRuntimeException
, e quindi si tratta di una unchecked exception che non ha bisogno di essere dichiarata nella clausolathrows
del metodo che la lancia. E quindi il metodoaggiungi
può essere modificato come segue:
public void aggiungi(Moneta moneta) throws PortaMonetePienoException { try { System.out.println("Proviamo ad aggiungere una " + moneta.getDescrizione()); } catch (NullPointerException exc) { throw new MonetaNullException(); } int indiceLibero = primoIndiceLibero(); if (indiceLibero == -1) { throw new PortaMonetePienoException("Portamonete pieno! La moneta " + moneta.getDescrizione() + " non è stata aggiunta..."); } else { monete[indiceLibero] = moneta; System.out.println("E' stata aggiunta una " + moneta.getDescrizione()); } }
-
Esercizio 8.l)
Consideriamo i sorgenti creati con gli esercizi realizzati per il capitolo 5. Modificare la classe
TestMonete
per gestire correttamente l'eccezionePortaMonetePienoException
.
Soluzione
Equivalentemente all'esercizio precedente il listato richiesto potrebbe essere il seguente:
/** * Classe di test per la classe Moneta. * * @author Claudio De Sio Cesari */ public class TestMonete { public static void main(String args[]) { Moneta monetaDaVentiCentesimi = new Moneta(20); Moneta monetaDaUnCentesimo = new Moneta(1); Moneta monetaDaUnEuro = new Moneta(100); // Creaiamo un portamonete con 11 monete PortaMonete portaMoneteInsufficiente = new PortaMonete(2, 5, 100, 10, 50, 10, 100, 200, 10, 5, 2); // Creaiamo un portamonete con 8 monete PortaMonete portaMonete = new PortaMonete(2, 5, 100, 10, 50, 10, 100, 200); portaMonete.stato(); try { // Aggiungiamo una moneta da 20 centesimi portaMonete.aggiungi(monetaDaVentiCentesimi); } catch (PortaMonetePienoException | MonetaNullException exc) { System.out.println(exc.getMessage()); } try { // Aggiungiamo la decima moneta da 1 centesimo. portaMonete.aggiungi(monetaDaUnCentesimo); } catch (PortaMonetePienoException | MonetaNullException exc) { System.out.println(exc.getMessage()); } try { // Aggiungiamo l'undicesima moneta (dovremmo ottenere un errore e la // moneta non sarà aggiunta) portaMonete.aggiungi(monetaDaUnEuro); } catch (PortaMonetePienoException | MonetaNullException exc) { System.out.println(exc.getMessage()); } // Valutiamo lo stato del portamonete. portaMonete.stato(); try { // preleviamo 20 centesimi portaMonete.preleva(monetaDaVentiCentesimi); } catch (MonetaNonTrovataException exc) { System.out.println(exc.getMessage()); } try { // Aggiungiamo l'undicesima moneta (dovremmo ottenere un errore e la // moneta non sarà aggiunta) portaMonete.aggiungi(monetaDaUnEuro); } catch (PortaMonetePienoException | MonetaNullException exc) { System.out.println(exc.getMessage()); } portaMonete.stato(); try { //Cerchiamo una moneta non esistente (dovremmo ottenere una stampa //di errore) portaMonete.preleva(new Moneta(7)); } catch (MonetaNonTrovataException exc) { System.out.println(exc.getMessage()); } try { //Proviamo ad aggiungere null portaMonete.aggiungi(null); } catch (PortaMonetePienoException | MonetaNullException exc) { System.out.println(exc.getMessage()); } try { //Proviamo a prelevare una moneta null portaMonete.preleva(null); } catch (MonetaNonTrovataException | MonetaNullException exc) { System.out.println(exc.getMessage()); } //Testiamo il passaggio di null al costruttore del porta monete PortaMonete portaMoneteEccezione = new PortaMonete(null); portaMonete.stato(); } }
Il cui output sarà:
Creata una moneta da 20 centesimi di EURO Creata una moneta da 1 centesimo di EURO Creata una moneta da 1 EURO Creata una moneta da 2 centesimi di EURO Creata una moneta da 5 centesimi di EURO Creata una moneta da 1 EURO Creata una moneta da 10 centesimi di EURO Creata una moneta da 50 centesimi di EURO Creata una moneta da 10 centesimi di EURO Creata una moneta da 1 EURO Creata una moneta da 2 EURO Creata una moneta da 10 centesimi di EURO Creata una moneta da 5 centesimi di EURO Sono state inserite solo le prime 10 monete! Creata una moneta da 2 centesimi di EURO Creata una moneta da 5 centesimi di EURO Creata una moneta da 1 EURO Creata una moneta da 10 centesimi di EURO Creata una moneta da 50 centesimi di EURO Creata una moneta da 10 centesimi di EURO Creata una moneta da 1 EURO Creata una moneta da 2 EURO Il portamonete contiene: Una moneta da 2 centesimi di EURO Una moneta da 5 centesimi di EURO Una moneta da 1 EURO Una moneta da 10 centesimi di EURO Una moneta da 50 centesimi di EURO Una moneta da 10 centesimi di EURO Una moneta da 1 EURO Una moneta da 2 EURO Proviamo ad aggiungere una moneta da 20 centesimi di EURO E' stata aggiunta una moneta da 20 centesimi di EURO Proviamo ad aggiungere una moneta da 1 centesimo di EURO E' stata aggiunta una moneta da 1 centesimo di EURO Proviamo ad aggiungere una moneta da 1 EURO Portamonete pieno! La moneta moneta da 1 EURO non è stata aggiunta... Il portamonete contiene: Una moneta da 2 centesimi di EURO Una moneta da 5 centesimi di EURO Una moneta da 1 EURO Una moneta da 10 centesimi di EURO Una moneta da 50 centesimi di EURO Una moneta da 10 centesimi di EURO Una moneta da 1 EURO Una moneta da 2 EURO Una moneta da 20 centesimi di EURO Una moneta da 1 centesimo di EURO Proviamo a prelevare una moneta da 20 centesimi di EURO Una moneta da 20 centesimi di EURO prelevata Proviamo ad aggiungere una moneta da 1 EURO E' stata aggiunta una moneta da 1 EURO Il portamonete contiene: Una moneta da 2 centesimi di EURO Una moneta da 5 centesimi di EURO Una moneta da 1 EURO Una moneta da 10 centesimi di EURO Una moneta da 50 centesimi di EURO Una moneta da 10 centesimi di EURO Una moneta da 1 EURO Una moneta da 2 EURO Una moneta da 1 EURO Una moneta da 1 centesimo di EURO Creata una moneta da 7 centesimi di EURO Proviamo a prelevare una moneta da 7 centesimi di EURO Moneta non trovata! La moneta passata era null La moneta passata era null Il portamonete è stato creato vuoto Il portamonete contiene: Una moneta da 2 centesimi di EURO Una moneta da 5 centesimi di EURO Una moneta da 1 EURO Una moneta da 10 centesimi di EURO Una moneta da 50 centesimi di EURO Una moneta da 10 centesimi di EURO Una moneta da 1 EURO Una moneta da 2 EURO Una moneta da 1 EURO Una moneta da 1 centesimo di EURO
-
Esercizio 8.m)
Aggiungere delle asserzioni nel costruttore della classe
PortaMonete
.
Soluzione
Potremmo modificare il listato di
PortaMonete
nel seguente modo:
public class PortaMonete { private static final int DIMENSIONE = 10; private final Moneta[] monete = new Moneta[DIMENSIONE]; public PortaMonete(int... valori) { assert monete.length == DIMENSIONE; try { int numeroMonete = valori.length; for (int i = 0; i < numeroMonete; i++) { if (i >= DIMENSIONE) { throw new PortaMonetePienoException( "Sono state inserite solo le prime + " + DIMENSIONE + " monete!"); } monete[i] = new Moneta(valori[i]); } // } catch (PortaMonetePienoException | NullPointerException exc) { } catch (PortaMonetePienoException exc) { System.out.println(exc.getMessage()); } catch (NullPointerException exc) { System.out.println("Il portamonete è stato creato vuoto"); } assert monete.length == DIMENSIONE; } //...
Si noti che abbiamo definito la costanteDIMENSIONE
impostata a 10. Poi come asserzioni abbiamo usato una pre-condizione e una post-condizione. In entrambi i casi abbiamo asserito lo stesso concetto: la lunghezza dell'array di monete è uguale al valore diDIMENSIONE
. Si noti anche come con queste semplici asserzioni stiamo rinforzando la logica del costruttore, è come se stessimo dicendo "qualsiasi cosa succeda, il valore della lunghezza dell'array non può cambiare". In questo modo il nostro codice rimarrà coerente con questa asserzione attraverso tutte le modifiche che verranno fatte in seguito. -
Esercizio 8.n)
Quali delle seguenti affermazioni sono corrette?
1.LeRuntimeException
sono equivalenti alle checked exception.
2.ArithmeticException
è una checked exception.
3.ClassCastException
è una unchecked exception.
4.NullPointerException
è una checked exception.
Soluzione
Solo l'affermazione numero 3 è corretta.
-
Esercizio 8.o)
Quali delle seguenti affermazioni sono corrette?
1. Nella clausolathrows
è possibile dichiarare solo le checked exception.
2. Nella clausolathrows
è possibile dichiarare solo le unchecked exception.
3. Nella clausolathrows
è possibile dichiarare unaNullPointerException
.
4. Con la clausolathrow
è possibile lanciare solo checked exception.
5. Con la clausolathrow
è possibile lanciare solo unchecked exception.
6. La clausolathrows
è obbligatoria se nel nostro metodo potrebbe essere lanciata una checked exception.
7. Un metodo che dichiara una clausolathrows
può essere invocato solo se si gestisce all'interno di un bloccotry
-catch
.
Soluzione
Sono corrette le affermazioni numero 3 e numero 6. Infatti la clausola
throws
e il comandothrow
possono essere utilizzati per ogni tipo di eccezione, e questo esclude che siano corrette le affermazioni 1, 2, 4 e 5. L'affermazione 7 è invece scorretta perché il metodo che invoca un metodo che dichiara la clausolathrows
, potrebbe a sua volta dichiarare la clausolathrows
. -
Esercizio 8.p)
Quali delle seguenti affermazioni sono corrette?
1. È possibile definire nuove eccezioni solo di tipo checked exception.
2. Se definiamo una sottoclasseMyException
diNullPointerException
, sarà possibile gestire un’eccezione di tipoNullPointerException
all’interno di una clausolacatch
aMyException
.
3. Se definiamo una sottoclasse diNullPointerException
, questa verrà catturata al posto dellaNullPointerException
.
4. Se definiamo una sottoclasse diArithmeticException
, questa verrà lanciata nel caso ci sia un problema in un'operazione aritmetica.
Soluzione
Nessuna delle affermazioni è corretta.
-
Esercizio 8.q)
Non tenendo conto del costrutto
try
-with-resources, il bloccofinally
è obbligatorio (scegliere tutte le affermazioni valide):1. Quando non ci sono blocchicatch
dopo un bloccotry
.
2. Quando non ci sono blocchitry
prima di un bloccocatch
.
3. Quando ci sono almeno due blocchicatch
dopo un bloccotry
.
4. Mai.
Soluzione
Solo la prima affermazione è corretta.
-
Esercizio 8.r)
Considerando il seguente metodo:
public void metodoCheLanciaEccezione() throws ArrayIndexOutOfBoundsException { //INSERIRE CODICE QUI }
Scegli tra i seguenti snippet quelli che potrebbero essere inseriti nel metodo
metodoCheLanciaEccezione
affinché il codice precedente sia valido:1.2.throw new ArrayIndexOutOfBoundsException ();
int i = 0, j = 0; try { i = i / j; } catch(ArithmeticException e) { throw new ArrayIndexOutOfBoundsException (); }
5.int i = 0;
System.out.println();
Soluzione
Tutti gli snippet sono validi perché, nella clausola
throws
, viene dichiarata laArrayIndexOutOfBoundsException
che è un'eccezione unchecked, e che quindi non è obbligatoria esplicitamente. Si noti che la risposta 2 fa scattare unaArithmeticException
, la gestisce e rilancia unaArrayIndexOutOfBoundsException
. -
Esercizio 8.s)
Considerando la seguente classe:
public class Esercizio8S { public static void main(String args[]) throws NullPointerException { Esercizio8S e = new Esercizio8S(); e.metodo(); } public NullPointerException metodo() throws Exception { String s = null; try { s.toString(); } catch(ArithmeticException e) { throw new NullPointerException (); } return null; } }
Scegliere tutte le affermazioni corrette:1. Il codice non compila perché il metodometodo
non può ritornareNullPointerException
.
2. Il codice non compila perché il metodometodo
ritornanull
e non unaNullPointerException
.
3. Il codice non compila perché il metodomain
non dichiara la giusta eccezione nella sua clausolathrows
.
4. Il codice compila ma al runtime termina con unaNullPointerException
.
5. Il codice compila ma al runtime termina con unaException
.
6. Il codice compila ma al runtime termina con unaArithmeticException
.
Soluzione
L'unica affermazione corretta è la 3. La sua correttezza esclude la correttezza delle affermazioni 4, 5 e 6. La 1 e la 2 sono false perché
NullPointerException
è comunque una classe. -
Esercizio 8.t)
Creare una classe
PortaAutomatica
che dichiari due metodi,open
eclose
, dove quest'ultimo deve essere compatibile per essere chiamato con la tecnica deltry
-with-resources.
Soluzione
Una semplice implementazione potrebbe essere la seguente:
public class PortaAutomatica implements AutoCloseable { public void close() { System.out.println("La porta si sta chiudendo"); } public void open() { System.out.println("La porta si sta aprendo"); } }
-
Esercizio 8.u)
Considerando la soluzione dell'esercizio 8.t (ovvero la classe
PortaAutomatica
) : scrivere una semplice classe che ne testi il funzionamento mediante il costruttotry
-with-resources.
Soluzione
La soluzione potrebbe essere semplice come la seguente:
public class Esercizio8U { public static void main(String args[]) { try (PortaAutomatica portaAutomatica = new PortaAutomatica();) { portaAutomatica.open(); } } }
il cui output, una volta eseguita, sarà:
La porta si sta aprendo La porta si sta chiudendo
-
Esercizio 8.v)
Riprendiamo l'esercizio 7.u dove avevamo verificato che le seguenti classi compilavano senza errori, ma che
SommaIntero
poteva lanciare un'eccezione al runtime.
public abstract class SommaNumero { public abstract Number somma (Number n1, Number n2); } public class SommaIntero extends SommaNumero { @Override public Integer somma(Number n1, Number n2) { return (Integer)n1 + (Integer)n2; } }
Infatti con le seguenti istruzioni:
SommaIntero sommaIntero = new SommaIntero(); sommaIntero.somma(1.0, 1.0);
otterremo quest'eccezione al runtime:
Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.Double cannot be cast to java.base/java.lang.Integer at SommaIntero.somma(SommaIntero.java:4) at SommaIntero.main(SommaIntero.java:9)
Nell'esercizio 7.v, avevamo chiesto di rendere robusta l'implementazione della classe
SommaIntero
, ed il risultato è stato il seguente:
public class SommaIntero extends SommaNumero { @Override public Integer somma(Number n1, Number n2) { if (n1 == null || n2 == null) { System.out.println("Impossibile sommare un operando null, " + "restituisco il valore di default"); return Integer.MIN_VALUE; } else if (!(n1 instanceof Integer && n2 instanceof Integer)) { System.out.println("Passa solo variabili di tipo intere, " + "restituisco il valore di default"); return Integer.MIN_VALUE; } return (Integer)n1 + (Integer)n2; } }
Ora che si conosce la teoria delle eccezioni, riprogettare la classe
SommaIntero
usando la gestione delle eccezioni.
Soluzione
La soluzione con la gestione delle eccezioni è indubbiamente più semplice ed elegante:
public class SommaIntero extends SommaNumero { @Override public Integer somma(Number n1, Number n2) { Integer risultato = null; try { risultato = (Integer)n1 + (Integer)n2; } catch (NullPointerException e) { System.out.println("Impossibile sommare un operando null"); } catch (ClassCastException e) { System.out.println("Passa solo variabili di tipo intere"); } return risultato; } }
Eseguendo il seguente metodomain
infatti:
public static void main(String args[]) { SommaIntero sommaIntero = new SommaIntero(); sommaIntero.somma(1.0, 1.0); sommaIntero.somma(null, 1.0); }
-
Esercizio 8.z)
Creare una semplice classe di test per la classe
SommaIntero
che abbiamo creato nell'esercizio 8.v.
Soluzione
Con la seguente classe di test:
public class Esercizio8Z { private static final String PREFISSO_FRASE ="Il risultato è "; public static void main(String args[]) { SommaIntero sommaIntero = new SommaIntero(); System.out.println(PREFISSO_FRASE + sommaIntero.somma(1.0, 1.0)); System.out.println(PREFISSO_FRASE + sommaIntero.somma(1, null)); System.out.println(PREFISSO_FRASE + sommaIntero.somma(1, 25)); } }
Possiamo verificare i casi possibili che abbiamo previsto.