CodeGym /Corsi /JAVA 25 SELF /Eccezioni come parte dell'API e try-with-resources

Eccezioni come parte dell'API e try-with-resources

JAVA 25 SELF
Livello 24, Lezione 4
Disponibile

1. Le eccezioni come parte dell'API

Perché le eccezioni fanno parte del «contratto» del metodo?

Quando scrivi un metodo, definisci non solo i parametri e il valore di ritorno, ma anche quali eccezioni può lanciare. Questo fa parte del «contratto» tra il tuo metodo e chi lo utilizzerà. Se il metodo può lanciare un'eccezione, chi lo chiama deve saperlo — per gestire correttamente l'errore (o almeno non stupirsi quando il programma termina improvvisamente con un errore).

Esempio:

public void readFile(String filename) throws IOException {
    // ... lettura del file
}

Qui è esplicitato che il metodo può lanciare IOException. È un segnale per l'utente del metodo: «Sii pronto a gestire l'errore di lettura del file!»

Documentare le eccezioni: tag @throws in Javadoc

Per fare in modo che altri sviluppatori capiscano quali eccezioni può lanciare il tuo metodo, usa il tag @throws (o @exception) in Javadoc.

Esempio:

/**
 * Legge il contenuto di un file.
 *
 * @param filename nome del file
 * @return contenuto del file come stringa
 * @throws IOException se si verifica un errore di lettura del file
 */
public String readFile(String filename) throws IOException {
    // ...
}

Perché è utile?

  • Aiuta altri sviluppatori a capire quali errori devono essere gestiti.
  • Le IDE e i generatori di documentazione (ad esempio, Javadoc) mostrano queste eccezioni direttamente nei suggerimenti.
  • Aumenta l'affidabilità e la prevedibilità del codice.

Eccezioni checked e unchecked nell'API

Le eccezioni checked (sottoclassi di Exception, ma non di RuntimeException) sono parte del contratto del metodo. Devono essere gestite oppure dichiarate esplicitamente (throws).

Le eccezioni unchecked (RuntimeException e sottoclassi) in genere segnalano errori di programmazione (ad esempio, NullPointerException, IllegalArgumentException). Non è obbligatorio indicarle nella firma, ma se il tuo metodo può lanciare un errore del genere (ad esempio per argomenti non validi), è comunque opportuno descriverlo nel Javadoc.

Esempio:

/**
 * Divide a per b.
 * @param a dividendo
 * @param b divisore
 * @return risultato della divisione
 * @throws IllegalArgumentException se b == 0
 */
public int divide(int a, int b) {
    if (b == 0) throw new IllegalArgumentException("Il divisore non può essere zero");
    return a / b;
}

Eccezioni e progettazione dell'API

  • Pensa all'utente del tuo metodo: quali errori può e deve gestire? Quali sono bug e quali situazioni «operative»?
  • Non abusare delle eccezioni checked: se l'errore è un bug (ad esempio, argomento non valido), è meglio lanciare un'eccezione unchecked.
  • Documenta tutte le eccezioni che possono essere propagate «verso l'alto».

2. Costrutto try-with-resources

Problema: come chiudere in modo sicuro le risorse?

In molti casi si lavora con risorse che devono essere necessariamente chiuse dopo l'uso: file, connessioni di rete, database, ecc. Se ci si dimentica di chiudere una risorsa, si possono avere perdite di memoria, lock su file o altri inconvenienti.

Prima:

BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("data.txt"));
    String line = reader.readLine();
    // ...
} catch (IOException e) {
    // gestione dell'errore
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            // gestione dell'errore in chiusura
        }
    }
}

Molto codice, facile sbagliare, si può dimenticare di chiudere la risorsa.

Soluzione: try-with-resources

Da Java 7 esiste il costrutto try-with-resources, che chiude automaticamente tutte le risorse, anche se all'interno del blocco si verifica un'eccezione.

Sintassi:

try (ResourceType resource = new ResourceType(...)) {
    // lavoro con la risorsa
} catch (ExceptionType e) {
    // gestione dell'errore
}

Esempio:

try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
    String line = reader.readLine();
    System.out.println(line);
} catch (IOException e) {
    System.out.println("Errore durante la lettura del file: " + e.getMessage());
}
// reader.close() verrà chiamato automaticamente!

Come funziona?

  • Nelle parentesi dopo try si dichiarano le risorse da chiudere.
  • Dopo l'uscita dal blocco try (anche se si verifica un'eccezione!) per ogni risorsa viene chiamato il metodo close().
  • Funziona solo per risorse che implementano l'interfaccia AutoCloseable (o la sua superinterfaccia Closeable).

Interfaccia AutoCloseable:

public interface AutoCloseable {
    void close() throws Exception;
}

Tutte le risorse standard di Java (file, stream, connessioni al DB) implementano questa interfaccia.

Si possono dichiarare più risorse

try (
    BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
    BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))
) {
    String line;
    while ((line = reader.readLine()) != null) {
        writer.write(line);
        writer.newLine();
    }
}

Entrambe le risorse verranno chiuse automaticamente, anche in caso di eccezione.

Vantaggi di try-with-resources

  • Sicurezza: le risorse vengono sempre chiuse, anche in caso di errori.
  • Concisione: meno codice, meno possibilità di sbagliare.
  • Leggibilità: è chiaro quali risorse vengono usate e quando vengono chiuse.

3. Pratica: scrivere codice sicuro con try-with-resources

Esempio: lettura di un file

public static void printFirstLine(String filename) {
    try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
        String line = reader.readLine();
        System.out.println("Prima riga: " + line);
    } catch (IOException e) {
        System.out.println("Errore: " + e.getMessage());
    }
}

Esempio: scrittura su file

public static void writeToFile(String filename, String text) {
    try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
        writer.write(text);
    } catch (IOException e) {
        System.out.println("Errore durante la scrittura: " + e.getMessage());
    }
}

Esempio: una risorsa personalizzata

Se scrivi una tua classe che deve essere chiusa, implementa semplicemente AutoCloseable:

public class MyResource implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("Risorsa chiusa!");
    }
}

Ora si può usare in try-with-resources:

try (MyResource res = new MyResource()) {
    // lavoro con la risorsa
} 

4. Errori tipici e best practice

Errore n. 1: dimenticare di chiudere la risorsa (senza try-with-resources).
Se non si usa try-with-resources, è facile dimenticare di chiudere un file o uno stream — questo porta a perdite di risorse.

Errore n. 2: tentare di usare try-with-resources con un oggetto che non implementa AutoCloseable.
Se la tua classe non implementa questa interfaccia, il compilatore non permetterà di usarla in try-with-resources.

Errore n. 3: non documentare le eccezioni nell'API.
Se il tuo metodo può lanciare un'eccezione, indica obbligatoriamente questo nella firma (throws) e in Javadoc (@throws). Aiuterà gli altri a usare correttamente il tuo codice.

Errore n. 4: catturare Exception invece di errori specifici.
È meglio catturare solo le eccezioni che ti aspetti realmente e che sai gestire.

1
Compito
JAVA 25 SELF, livello 24, lezione 4
Bloccato
Aggregatore di notizie: Lettura automatica del titolo dell'articolo
Aggregatore di notizie: Lettura automatica del titolo dell'articolo
1
Compito
JAVA 25 SELF, livello 24, lezione 4
Bloccato
Artefatto magico: Spegnimento autonomo
Artefatto magico: Spegnimento autonomo
1
Compito
JAVA 25 SELF, livello 24, lezione 4
Bloccato
Laboratorio scientifico: documentare i potenziali problemi nei dati
Laboratorio scientifico: documentare i potenziali problemi nei dati
1
Compito
JAVA 25 SELF, livello 24, lezione 4
Bloccato
Archivista digitale: Copia sicura di manoscritti antichi
Archivista digitale: Copia sicura di manoscritti antichi
1
Sondaggio/quiz
Gerarchia delle eccezioni, livello 24, lezione 4
Non disponibile
Gerarchia delle eccezioni
Lavoro avanzato con le eccezioni
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION