try-with-resources în Java

Excepții Java 7 (variabile existente în paranteze: Java 9)

try-with-resources deschide resurse (fișiere, conexiuni) în paranteze și le închide automat la final, chiar dacă apare o excepție.

Sintaxă
try (BufferedReader in = Files.newBufferedReader(cale);
     BufferedWriter out = Files.newBufferedWriter(alta)) {
    // folosești resursele
}   // in și out se închid automat, în ordine inversă

Ce face try-with-resources

Fișierele, conexiunile la baze de date și socket-urile trebuie închise după folosire, altfel rămân blocate resurse ale sistemului. În loc de un finally lung cu close() și verificări de null, declari resursele în parantezele lui try. La ieșirea din bloc, normal sau cu excepție, Java apelează automat close().

Merge cu orice obiect care implementează AutoCloseable (sau Closeable). Mai multe resurse se separă cu ; și se închid în ordine inversă deschiderii. Poți adăuga catch și finally, care rulează după închidere. Din Java 9 poți pune în paranteze și o variabilă deja declarată, dacă e efectiv finală.

Dacă și blocul, și close() aruncă excepții, se propagă cea din bloc, iar cea de la închidere este atașată ca „suprimată” (getSuppressed()), deci nu se pierde nicio informație.

Exemple

Exemplul 1: Scriere și citire de fișier

Writer-ul și reader-ul se închid automat la finalul fiecărui try. Fișierul note.txt se creează în directorul curent.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) throws IOException {
        Path fisier = Path.of("note.txt");

        try (BufferedWriter out = Files.newBufferedWriter(fisier)) {
            out.write("Ana;9.50\n");
            out.write("Bogdan;7.25\n");
            out.write("Corina;10\n");
        }

        try (BufferedReader in = Files.newBufferedReader(fisier)) {
            String linie;
            while ((linie = in.readLine()) != null) {
                String[] parti = linie.split(";");
                System.out.println(parti[0] + " are nota " + parti[1]);
            }
        }
    }
}

Rezultat

Ana are nota 9.50
Bogdan are nota 7.25
Corina are nota 10

Exemplul 2: Ordinea închiderii și o resursă proprie

Conexiune implementează AutoCloseable. Resursele se închid în ordine inversă (B, apoi A), înainte de catch și finally.

class Conexiune implements AutoCloseable {
    private final String nume;

    Conexiune(String nume) {
        this.nume = nume;
        System.out.println("deschid " + nume);
    }

    void trimite(String mesaj) {
        if (mesaj.isEmpty()) {
            throw new IllegalArgumentException("mesaj gol");
        }
        System.out.println(nume + " trimite: " + mesaj);
    }

    @Override
    public void close() {
        System.out.println("închid " + nume);
    }
}

public class Main {
    public static void main(String[] args) {
        try (Conexiune a = new Conexiune("A"); Conexiune b = new Conexiune("B")) {
            a.trimite("comanda 1024");
            b.trimite("");
        } catch (IllegalArgumentException e) {
            System.out.println("catch: " + e.getMessage());
        } finally {
            System.out.println("finally");
        }
    }
}

Rezultat

deschid A
deschid B
A trimite: comanda 1024
închid B
închid A
catch: mesaj gol
finally

Exemplul 3: Excepții suprimate

Blocul aruncă o excepție și apoi și close() aruncă una. Se propagă prima, iar a doua apare în getSuppressed().

class Imprimanta implements AutoCloseable {
    void tipareste(String doc) {
        throw new IllegalStateException("hârtie blocată la " + doc);
    }

    @Override
    public void close() {
        throw new IllegalStateException("capacul nu se închide");
    }
}

public class Main {
    public static void main(String[] args) {
        try (Imprimanta p = new Imprimanta()) {
            p.tipareste("factura.pdf");
        } catch (IllegalStateException e) {
            System.out.println("principală: " + e.getMessage());
            for (Throwable s : e.getSuppressed()) {
                System.out.println("suprimată: " + s.getMessage());
            }
        }
    }
}

Rezultat

principală: hârtie blocată la factura.pdf
suprimată: capacul nu se închide

Greșeli frecvente

  • Deschizi fișierul fără try și uiți close(); pe Windows fișierul rămâne blocat, iar la multe deschideri apare Too many open files.
  • Declari o resursă pe care nu o folosești în bloc: -Xlint dă [try] auto-closeable resource x is never referenced in body of corresponding try statement.
  • Pui în paranteze un obiect care nu implementează AutoCloseable: incompatible types: try-with-resources not applicable to variable type.

Comenzi înrudite

  • try, catch și finally: try încearcă un bloc de cod, catch prinde și tratează excepțiile aruncate în el, iar finally rulează mereu la ieșire.
  • Excepții verificate și neverificate: Excepțiile verificate (Exception) trebuie prinse sau declarate cu throws; cele neverificate (RuntimeException) nu sunt cerute de compilator.
  • throw și throws: throw aruncă o excepție acum; throws, în antetul metodei, anunță ce excepții verificate poate arunca metoda.
  • Files: Clasa cu metode statice pentru lucrul cu fișiere și foldere: citire, scriere, copiere, mutare, ștergere, listare.
  • BufferedReader: Citește text eficient, rând cu rând, dintr-un fișier, de la tastatură sau din alt Reader; close închide sursa.