Eccezioni controllate e non controllate
Fa parte della sezione Programmazione orientata agli oggetti del percorso Java di Coddy. Lezione 61 di 87.
Hai visto che la gerarchia delle eccezioni di Java si divide in rami diversi. La distinzione fondamentale che devi comprendere è tra eccezioni verificate e non verificate. Questo influisce sul modo in cui devi gestirle nel tuo codice.
Le eccezioni verificate sono eccezioni che il compilatore ti obbliga a gestire. Estendono direttamente Exception (non tramite RuntimeException). Devi intercettarle oppure dichiararle con throws:
// È necessario gestire IOException: è un'eccezione controllata
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // Può lanciare IOException
}
// Oppure intercettarla
public void readFileSafe(String path) {
try {
FileReader reader = new FileReader(path);
} catch (IOException e) {
System.out.println("File error: " + e.getMessage());
}
}Le eccezioni non controllate estendono RuntimeException. Il compilatore non richiede di gestirle. In genere indicano errori di programmazione, come riferimenti null o accessi non validi agli array:
// Non è necessaria una dichiarazione throws
public int divide(int a, int b) {
return a / b; // Può generare ArithmeticException (non controllata)
}
String name = null;
name.length(); // NullPointerException (non controllata)Quando crei eccezioni personalizzate, scegli la classe genitore in base a come vuoi che chi le chiama le gestisca. Usa eccezioni controllate per condizioni recuperabili che chi le chiama dovrebbe prevedere. Usa eccezioni non controllate per errori di programmazione che non dovrebbero verificarsi in un codice corretto.
Sfida
FacileCostruiamo un sistema di verifica dell’età che mostra la differenza fondamentale tra eccezioni controllate e non controllate! Creerai eccezioni personalizzate di entrambi i tipi e vedrai come il compilatore le tratta in modo diverso.
Organizzerai il codice in quattro file:
InvalidAgeException.java: Crea un’eccezione controllata per gli errori di convalida dell’età. Questa eccezione deve estendere direttamenteException, il che significa che i chiamanti saranno obbligati a gestirla. Includi un costruttore che accetta un messaggio e lo passa alla classe genitore.NegativeAgeException.java: Crea un’eccezione non controllata per quando qualcuno fornisce un’età negativa (un errore di programmazione che non dovrebbe verificarsi con un input corretto). Questa deve estendereRuntimeException. Includi un costruttore che accetta un messaggio e lo passa alla classe genitore.AgeVerifier.java: Crea una classe che convalida le età usando entrambi i tipi di eccezione. Includi due metodi statici:verifyAge(int age)- Questo metodo deve generareNegativeAgeException(non controllata) con il messaggio"Age cannot be negative: [age]"se l’età è inferiore a 0. Se l’età è inferiore a 18, generaInvalidAgeException(controllata) con il messaggio"Must be 18 or older: [age]". Altrimenti, stampaAge [age] verified successfully. Poiché questo metodo genera un’eccezione controllata, devi dichiararlo conthrows InvalidAgeException.verifyAgeUncheckedOnly(int age)- Questo metodo usa solo eccezioni non controllate. Se l’età è negativa, generaNegativeAgeExceptioncon lo stesso formato di messaggio. Se l’età è inferiore a 18, genera un’IllegalArgumentExceptioncon il messaggio"Too young: [age]". Altrimenti, stampaAge [age] verified (unchecked method). Nota che questo metodo non richiede alcuna dichiarazionethrows!Main.java: Metti insieme il tuo sistema di verifica! Riceverai un input: un’età (intero).Per prima cosa, stampa
=== Checked Exception Method ===e chiamaverifyAgecon l’età inserita. Poiché genera un’eccezione controllata, devi inserirla in un blocco try-catch. IntercettaInvalidAgeExceptione stampaChecked exception caught: [message]. Intercetta ancheNegativeAgeExceptione stampaUnchecked exception caught: [message].Poi stampa una riga vuota e
=== Unchecked Exception Method ===. ChiamaverifyAgeUncheckedOnlycon la stessa età. Anche se questo metodo può generare eccezioni, non sei obbligato a intercettarle. Tuttavia, inseriscilo comunque in un blocco try-catch per gestire gli errori in modo appropriato. IntercettaNegativeAgeExceptione stampaRuntime exception caught: [message]. IntercettaIllegalArgumentExceptione stampaIllegal argument caught: [message].
Riceverai un input: un intero che rappresenta l’età da verificare.
Nota la differenza fondamentale: il metodo con l’eccezione controllata richiede una dichiarazione throws e obbliga i chiamanti a gestirla, mentre il metodo con eccezioni non controllate viene compilato correttamente senza alcuna gestione delle eccezioni. Questa è la distinzione fondamentale tra eccezioni controllate e non controllate in Java!
Provalo tu
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int age = scanner.nextInt();
// TODO: testa il metodo con eccezione controllata
// Stampa: "=== Checked Exception Method ==="
// Chiama AgeVerifier.verifyAge(age) in un blocco try-catch
// - Intercetta InvalidAgeException: stampa "Checked exception caught: [message]"
// - Intercetta NegativeAgeException: stampa "Unchecked exception caught: [message]"
// TODO: stampa una riga vuota, poi "=== Unchecked Exception Method ==="
// Chiama AgeVerifier.verifyAgeUncheckedOnly(age) in un blocco try-catch
// - Intercetta NegativeAgeException: stampa "Runtime exception caught: [message]"
// - Intercetta IllegalArgumentException: stampa "Illegal argument caught: [message]"
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione a oggetti
File esterniIntroduzione alla programmazione a oggettiClassi e oggettiLa parola chiave thisMetodiCampi (attributi)Metodo costruttoreSovraccarico dei costruttoriRipasso - Calcolatrice semplice4Ereditarietà
Ereditarietà di base (extends)La parola chiave superSovrascrittura dei metodi (@Override)Concatenamento dei costruttoriLa classe ObjectEreditarietà singola e multilivelloPerché non esiste l'ereditarietà multipla delle classiRiepilogo: gerarchia dei dipendenti7Metodi speciali e classe Object
Metodo toString()equals() e hashCode()Metodo clone()compareTo() e ComparableInterfaccia ComparatorRiepilogo - Ordinamento personalizzato10Gestione delle eccezioni in OOP
Gerarchia delle classi di eccezioneEccezioni personalizzateEccezioni controllate e non controllatePattern try-with-resourcesRiepilogo - Utente validato2Modificatori di accesso e incapsulamento
Panoramica dei livelli di accessoMetodi getter e setterNascondimento delle informazioniLa parola chiave finalRiepilogo - Gestore di conti bancari5Polimorfismo
Nozioni di base sull'overloading dei metodiOverride dei metodi (a runtime)Upcasting e downcastingL'operatore instanceofClassi e metodi astrattiRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàAggregazione vs composizioneClassi interne, annidate e anonimeEnum e metodi degli EnumRecord (Java 16+)Classi sealed (Java 17+)11Modelli di progettazione Parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern BuilderPattern ObserverPattern Strategy3Proprietà di classe e membri statici
Variabili di istanza e staticheMetodi staticiBlocchi staticiCostanti (static final)Riepilogo - Contatore e utility6Interfacce e classi astratte
Introduzione alle interfacceImplementazione delle interfacceImplementazione di più interfacceMetodi default e static nelle interfacceClassi astratte e interfacce a confrontoInterfacce funzionaliRiepilogo: sistema di pagamento9Tipi generici
Introduzione ai tipi genericiClassi genericheMetodi genericiParametri di tipo con limitiCaratteri jolly (?, extends, super)Riepilogo - Contenitore generico12Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern IteratorEsercitati da solo: Compilatore Java online