CodeGym /Corsi /JAVA 25 SELF /finally e throw: finalizzazione e generazione delle eccez...

finally e throw: finalizzazione e generazione delle eccezioni

JAVA 25 SELF
Livello 11 , Lezione 3
Disponibile

1. Introduzione al blocco finally

Quando lavori con risorse — file, connessioni di rete, database — è importante essere sicuri che vengano chiuse o rilasciate sempre, anche se durante l'esecuzione si verifica un errore. In Java esiste un blocco speciale — finally.

Come funziona finally?

Il blocco finally è parte della costruzione try-catch-finally. Il codice dentro finally viene eseguito sempre (se presente) — indipendentemente dal fatto che si sia verificata un'eccezione oppure no. Anche se in try c'è un return o viene lanciata un'eccezione — finally verrà comunque eseguito (a meno che non si spenga il computer o non si termini forzatamente il programma tramite System.exit(0)).

Sintassi:

try {
    // Codice in cui può verificarsi un'eccezione
} catch (ExceptionType e) {
    // Gestione dell'errore
} finally {
    // Questo codice verrà eseguito sempre!
}

Esempio

try {
    System.out.println("Inizio del lavoro");
    int result = 10 / 0; // qui si verificherà un errore
    System.out.println("Risultato: " + result);
} catch (ArithmeticException e) {
    System.out.println("Errore: divisione per zero");
} finally {
    System.out.println("Questo codice verrà eseguito in ogni caso");
}

Output:

Inizio del lavoro
Errore: divisione per zero
Questo codice verrà eseguito in ogni caso

Cosa succede?

  1. Nel try proviamo a dividere due numeri e otteniamo un errore.
  2. Se durante la divisione si verifica un errore — catch lo gestirà.
  3. Ma! In ogni caso finally verrà eseguito e scriverà un messaggio in console.

2. finally senza catch

Esistono 3 varianti della costruzione:

  • Completa: try-catch-finally
  • Senza finally: try-catch
  • Senza catch: try-finally

La terza variante si usa quando a intercettare e gestire l'errore sarà un metodo a un livello superiore. Ma il blocco finally serve per garantire l'esecuzione di un determinato codice:

  • Chiusura di file, connessioni di rete, database.
  • Rilascio di qualunque risorsa (ad esempio, lock).
  • Logging: registrazione di informazioni sulla conclusione dell'operazione.

Esempio:

try {
    System.out.println("Dividiamo i numeri");
    int result = 10 / 0;   // errore!
    System.out.println("Risultato: " + result);
} finally {
    System.out.println("Blocco finally eseguito");
}

Risultato:

Dividiamo i numeri
Blocco finally eseguito
Exception in thread "main" java.lang.ArithmeticException: / by zero

Quando finally NON viene eseguito?

Viene eseguito quasi sempre. Fanno eccezione i casi in cui:

  1. Il programma è stato terminato forzatamente con: System.exit(0).
  2. Il thread in cui si esegue finally è stato «ucciso» forzatamente.
  3. Il computer è stato spento.

3. L'operatore throw: come generare un'eccezione manualmente

A volte Java «lancia» eccezioni da sola (ad esempio, divisione per zero, accesso oltre i limiti dell'array). Ma ci sono situazioni in cui tu vuoi dichiarare esplicitamente: «È un errore! Non posso continuare l'esecuzione!». Per questo in Java c'è l'operatore throw.

Analogia: Se sei in un negozio e vedi merce scaduta — «lanci» un reclamo. Così nel codice: se qualcosa non va — lanci un'eccezione.

Sintassi di throw

throw new ExceptionType("Messaggio di errore");

ExceptionType — qualsiasi classe che estende Throwable (di solito Exception o RuntimeException). Tra le parentesi c'è un messaggio che aiuta a capire cosa non ha funzionato.

Esempio: validazione degli argomenti del metodo

public static int safeDivide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Il divisore non può essere zero");
    }
    return a / b;
}

Utilizzo:

public static void main(String[] args) {
    try {
        int result = safeDivide(10, 0);
        System.out.println("Risultato: " + result);
    } catch (IllegalArgumentException e) {
        System.out.println("Errore: " + e.getMessage());
    }
}

Risultato:

Errore: Il divisore non può essere zero

Quando usare throw?

  • Validazione degli argomenti del metodo (ad esempio, se è arrivato null o dati non validi).
  • Verifica dello stato dell'oggetto (ad esempio, tentare di prelevare denaro da un conto con 0 euro).
  • All'interno di catch — se vuoi «rilanciare» l'eccezione più in alto (ad esempio, per aggiungere informazioni).

4. Combinare try-catch-finally e throw

Talvolta queste costruzioni lavorano insieme. Per esempio, intercetti un errore, ma dopo decidi di lanciarne uno tuo, più informativo.

public static int parseAndDivide(String text, int divisor) {
    try {
        int number = Integer.parseInt(text);
        if (divisor == 0) {
            throw new IllegalArgumentException("Il divisore non può essere zero");
        }
        return number / divisor;
    } catch (NumberFormatException e) {
        throw new IllegalArgumentException("La stringa '" + text + "' non è un numero");
    } finally {
        System.out.println("Tentativo di elaborare la stringa: " + text);
    }
}

Utilizzo:

try {
    int result = parseAndDivide("42a", 2);
    System.out.println("Risultato: " + result);
} catch (IllegalArgumentException e) {
    System.out.println("Errore: " + e.getMessage());
}

Risultato:

Tentativo di elaborare la stringa: 42a
Errore: La stringa '42a' non è un numero

Dettaglio importante: return e finally

Anche se nel blocco try c'è un return, finally verrà comunque eseguito!

public static int getValue() {
    try {
        return 10;
    } finally {
        System.out.println("finally verrà eseguito comunque!");
    }
}

La chiamata a getValue() stamperà:

finally verrà eseguito comunque!

5. Errori tipici nell'uso di finally e throw

Errore n. 1: hai dimenticato di chiudere una risorsa senza finally.
Problema molto comune: hai aperto un file, non l'hai chiuso — perdita di risorse. Usa sempre finally (oppure try-with-resources, di cui parleremo più avanti).

Errore n. 2: hai lanciato un'eccezione ma non l'hai gestita.
Se lanci un'eccezione con throw, ma non la intercetti da nessuna parte (non c'è try-catch), il programma terminerà in modo anomalo. Pensa sempre a chi intercetterà la tua eccezione.

Errore n. 3: return dentro finally.
Se per errore hai scritto return dentro finally, esso «sovrascriverà» tutti i precedenti return o throw. Questo può portare a bug molto difficili da individuare. È fortemente sconsigliato!

public int tricky() {
    try {
        return 1;
    } finally {
        return 2; // PERICOLOSO: verrà restituito 2, non 1!
    }
}

Risultato: verrà restituito 2, sebbene in try ci fosse 1.

Errore n. 4: perdita di informazioni sull'eccezione.
Se intercetti un'eccezione e poi ne lanci una nuova, senza conservare le informazioni sulla precedente (e), perdi lo stack di chiamate, il che rende più difficile il debug. Meglio scrivere così:

catch (NumberFormatException e) {
    throw new IllegalArgumentException("Errore di conversione", e);
}
1
Compito
JAVA 25 SELF, livello 11, lezione 3
Bloccato
Robot aspirapolvere e il suo rapporto di completamento 🧹
Robot aspirapolvere e il suo rapporto di completamento 🧹
1
Compito
JAVA 25 SELF, livello 11, lezione 3
Bloccato
Sistema di punteggio: solo valori positivi! 🏅
Sistema di punteggio: solo valori positivi! 🏅
1
Compito
JAVA 25 SELF, livello 11, lezione 3
Bloccato
Modulo critico e terminazione di emergenza con report 💥
Modulo critico e terminazione di emergenza con report 💥
1
Compito
JAVA 25 SELF, livello 11, lezione 3
Bloccato
Validazione del nome utente nel sistema di registrazione 📝
Validazione del nome utente nel sistema di registrazione 📝
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION