W tym samouczku nauczymy się instrukcji try-with-resources, aby automatycznie zamknąć zasoby.
try-with-resources
Oświadczenie automatycznie zamyka wszystkie zasoby na końcu instrukcji. Zasób to obiekt, który ma zostać zamknięty na końcu programu.
Jego składnia to:
try (resource declaration) ( // use of the resource ) catch (ExceptionType e1) ( // catch block )
Jak widać z powyższej składni, deklarujemy try-with-resources
instrukcję przez,
- deklarowanie i tworzenie wystąpienia zasobu w
try
klauzuli. - określanie i obsługa wszystkich wyjątków, które mogą zostać zgłoszone podczas zamykania zasobu.
Uwaga: Instrukcja try-with-resources zamyka wszystkie zasoby, które implementują interfejs AutoCloseable.
Weźmy przykład, który implementuje try-with-resources
instrukcję.
Przykład 1: try-with-resources
import java.io.*; class Main ( public static void main(String() args) ( String line; try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) ( while ((line = br.readLine()) != null) ( System.out.println("Line =>"+line); ) ) catch (IOException e) ( System.out.println("IOException in try block =>" + e.getMessage()); ) ) )
Dane wyjściowe, jeśli nie znaleziono pliku test.txt.
IOException w try-with-resources block => test.txt (Brak takiego pliku lub katalogu)
Dane wyjściowe, jeśli zostanie znaleziony plik test.txt.
Wprowadzanie bloku try-with-resources Line => test line
W tym przykładzie używamy wystąpienia BufferedReader do odczytu danych z test.txt
pliku.
Deklarowanie i tworzenie wystąpienia BufferedReader wewnątrz try-with-resources
instrukcji zapewnia, że jego wystąpienie zostanie zamknięte, niezależnie od tego, czy try
instrukcja kończy się normalnie, czy zgłasza wyjątek.
Jeśli wystąpi wyjątek, można go obsłużyć za pomocą bloków obsługi wyjątków lub słowa kluczowego throws.
Stłumione wyjątki
W powyższym przykładzie wyjątki można wyrzucić z try-with-resources
instrukcji, gdy:
- Plik
test.txt
nie został znaleziony. - Zamknięcie
BufferedReader
obiektu.
Z try
bloku można również wyrzucić wyjątek, ponieważ odczyt pliku może się nie powieść z wielu powodów w dowolnym momencie.
Jeśli wyjątki są generowane zarówno z try
bloku, jak i try-with-resources
instrukcji, zostanie zgłoszony wyjątek z try
bloku, a wyjątek z try-with-resources
instrukcji zostanie pominięty.
Pobieranie wyłączonych wyjątków
W Javie 7 i nowszych wersjach pominięte wyjątki można pobrać, wywołując Throwable.getSuppressed()
metodę z wyjątku zgłoszonego przez try
blok.
Ta metoda zwraca tablicę wszystkich pominiętych wyjątków. Otrzymujemy wyłączone wyjątki w catch
bloku.
catch(IOException e) ( System.out.println("Thrown exception=>" + e.getMessage()); Throwable() suppressedExceptions = e.getSuppressed(); for (int i=0; i" + suppressedExceptions(i)); ) )
Zalety korzystania z zasobów „try-with-resources”
Oto zalety korzystania z zasobów typu Try-with-Resources:
1. ostatecznie blok nie jest wymagany do zamknięcia zasobu
Zanim Java 7 wprowadziła tę funkcję, musieliśmy użyć finally
bloku, aby upewnić się, że zasób jest zamknięty, aby uniknąć wycieków zasobów.
Oto program podobny do przykładu 1 . Jednak w tym programie ostatecznie użyliśmy bloku do zamknięcia zasobów.
Przykład 2: Zamknij zasób za pomocą final block
import java.io.*; class Main ( public static void main(String() args) ( BufferedReader br = null; String line; try ( System.out.println("Entering try block"); br = new BufferedReader(new FileReader("test.txt")); while ((line = br.readLine()) != null) ( System.out.println("Line =>"+line); ) ) catch (IOException e) ( System.out.println("IOException in try block =>" + e.getMessage()); ) finally ( System.out.println("Entering finally block"); try ( if (br != null) ( br.close(); ) ) catch (IOException e) ( System.out.println("IOException in finally block =>"+e.getMessage()); ) ) ) )
Wynik
Wchodzenie do try block Line => line z pliku test.txt Wchodzenie na koniec blok
Jak widać z powyższego przykładu, użycie finally
bloku do czyszczenia zasobów sprawia, że kod jest bardziej złożony.
Zwróć uwagę na try… catch
blok w finally
bloku? Dzieje się tak, ponieważ IOException
może również wystąpić podczas zamykania BufferedReader
instancji w tym finally
bloku, więc jest ona również przechwytywana i obsługiwana.
try-with-resources
Oświadczenie robi automatyczne zarządzanie zasobami . Nie musimy jawnie zamykać zasobów, ponieważ JVM automatycznie je zamyka. Dzięki temu kod jest bardziej czytelny i łatwiejszy do napisania.
2. spróbuj z zasobami z wieloma zasobami
W try-with-resources
instrukcji możemy zadeklarować więcej niż jeden zasób, oddzielając je średnikiem;
Przykład 3: spróbuj z wieloma zasobami
import java.io.*; import java.util.*; class Main ( public static void main(String() args) throws IOException( try (Scanner scanner = new Scanner(new File("testRead.txt")); PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) ( while (scanner.hasNext()) ( writer.print(scanner.nextLine()); ) ) ) )
Jeśli ten program jest wykonywany bez generowania żadnych wyjątków, Scanner
obiekt odczytuje wiersz z testRead.txt
pliku i zapisuje go w nowym testWrite.txt
pliku.
W przypadku wielu deklaracji try-with-resources
instrukcja zamyka te zasoby w odwrotnej kolejności. W tym przykładzie PrintWriter
obiekt jest najpierw zamykany, a następnie Scanner
zamykany.
Ulepszenie próbowania z zasobami Java 9
W Javie 7 występuje ograniczenie do try-with-resources
instrukcji. Zasób należy zadeklarować lokalnie w swoim bloku.
try (Scanner scanner = new Scanner(new File("testRead.txt"))) ( // code )
Gdybyśmy zadeklarowali zasób poza blokiem w Javie 7, wygenerowałoby to komunikat o błędzie.
Scanner scanner = new Scanner(new File("testRead.txt")); try (scanner) ( // code )
Aby poradzić sobie z tym błędem, Java 9 poprawiła try-with-resources
instrukcję, tak aby można było użyć odwołania do zasobu, nawet jeśli nie jest zadeklarowane lokalnie. Powyższy kod będzie teraz wykonywany bez błędu kompilacji.