Wzorzec try-with-resources
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 62 z 87.
Podczas pracy z zasobami takimi jak strumienie plików lub połączenia z bazą danych musisz zawsze je zamykać po zakończeniu pracy. W przeciwnym razie ryzykujesz wycieki pamięci. Tradycyjne podejście wykorzystuje blok finally, ale jest rozwlekłe i podatne na błędy.
Instrukcja try-with-resources w Javie automatycznie zamyka zasoby po zakończeniu bloku. Każda klasa implementująca interfejs AutoCloseable może być używana z tą składnią:
// Tradycyjne podejście – rozwlekłe i ryzykowne
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} finally {
if (reader != null) {
reader.close(); // To również może zgłosić wyjątek!
}
}
// Try-with-resources – zwięzłe i bezpieczne
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
} // Tutaj następuje automatyczne zamknięcieMożesz zarządzać wieloma zasobami, oddzielając je średnikami. Są zamykane w odwrotnej kolejności niż zostały zadeklarowane:
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
// Użyj obu zasobów
} // Najpierw zamykany jest br, a potem frAby utworzyć własną klasę, którą można automatycznie zamykać, zaimplementuj interfejs AutoCloseable i jego jedyną metodę close():
public class DatabaseConnection implements AutoCloseable {
public DatabaseConnection() {
System.out.println("Connection opened");
}
@Override
public void close() {
System.out.println("Connection closed");
}
}Ten wzorzec zapewnia prawidłowe zwalnianie zasobów, nawet jeśli podczas przetwarzania wystąpią wyjątki.
Wyzwanie
ŁatwyStwórzmy system zarządzania zasobami, który pokaże możliwości konstrukcji try-with-resources! Utworzysz własne klasy automatycznie zamykające się, które symulują zarządzanie połączeniami i sesjami, zapewniając ich prawidłowe zamknięcie.
Rozmieścisz kod w trzech plikach:
Connection.java: Utwórz klasę symulującą połączenie z bazą danych. Twoja klasaConnectionpowinna implementowaćAutoCloseable. Powinna zawierać prywatne pole przechowujące nazwę połączenia (String), konstruktor, który przyjmuje nazwę i wyświetla[name] connection opened, metodęquery(String sql), która wyświetlaExecuting on [name]: [sql], oraz wymaganą metodęclose(), która wyświetla[name] connection closed.Session.java: Utwórz kolejną klasę automatycznie zamykającą się, która symuluje sesję użytkownika. Twoja klasaSessionrównież powinna implementowaćAutoCloseable. Dodaj prywatne pole przechowujące nazwę użytkownika (String), konstruktor, który przyjmuje nazwę użytkownika i wyświetlaSession started for [username], metodęperformAction(String action), która wyświetla[username] performed: [action], oraz metodęclose(), która wyświetlaSession ended for [username].Main.java: Połącz elementy systemu zarządzania zasobami! Otrzymasz trzy dane wejściowe: nazwę połączenia, nazwę użytkownika i akcję do wykonania.Najpierw zademonstruj zarządzanie pojedynczym zasobem. Wyświetl
=== Single Resource ===, a następnie użyj konstrukcji try-with-resources, aby utworzyć obiektConnectionz podaną nazwą. Wewnątrz bloku try wywołajquery("SELECT * FROM users"). Połączenie powinno zamknąć się automatycznie po zakończeniu bloku.Następnie zademonstruj zarządzanie wieloma zasobami. Wyświetl pusty wiersz, a potem
=== Multiple Resources ===. Użyj konstrukcji try-with-resources z obiektamiConnection(używając tej samej nazwy) orazSession(używając nazwy użytkownika), zadeklarowanymi w tej kolejności i rozdzielonymi średnikami. Wewnątrz bloku try najpierw wywołaj na połączeniu metodęquery("INSERT INTO logs"), a następnie wywołaj na sesji metodęperformAction, przekazując jej akcję z danych wejściowych. Zwróć uwagę, że zasoby zamykają się w odwrotnej kolejności!
Otrzymasz trzy dane wejściowe w następującej kolejności: nazwę połączenia (String), nazwę użytkownika (String) i akcję (String).
Zauważ, że konstrukcja try-with-resources eliminuje potrzebę jawnego wywoływania metod close i używania bloków finally. Zasoby na pewno zostaną zamknięte, nawet jeśli wystąpią wyjątki, a wiele zasobów zamyka się w odwrotnej kolejności ich deklaracji!
Spróbuj swoich sił
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String connectionName = scanner.nextLine();
String username = scanner.nextLine();
String action = scanner.nextLine();
// === Single Resource ===
// TODO: Wypisz nagłówek
// TODO: Użyj try-with-resources, aby utworzyć Connection
// TODO: Wewnątrz bloku try wywołaj query("SELECT * FROM users")
// === Multiple Resources ===
// TODO: Wypisz pusty wiersz i nagłówek
// TODO: Użyj try-with-resources zarówno dla Connection, jak i Session
// TODO: Wewnątrz bloku try:
// - Wywołaj query("INSERT INTO logs") na połączeniu
// - Wywołaj performAction na sesji, przekazując wczytaną akcję
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe thisMetodyPola (atrybuty)Metoda konstruktoraPrzeciążanie konstruktoraPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawy dziedziczenia (extends)Słowo kluczowe superPrzesłanianie metod (@Override)Łańcuch wywołań konstruktorówKlasa ObjectDziedziczenie jedno- i wielopoziomoweDlaczego Java nie obsługuje wielodziedziczenia klasPodsumowanie – hierarchia pracowników7Metody specjalne i klasa Object
Metoda toString()equals() i hashCode()Metoda clone()compareTo() i ComparableInterfejs ComparatorPodsumowanie — własne sortowanie10Obsługa wyjątków w programowaniu obiektowym
Hierarchia klas wyjątkówWłasne wyjątkiBłędy sprawdzane a niesprawdzaneWzorzec try-with-resourcesPodsumowanie – zweryfikowany użytkownik2Modyfikatory dostępu i enkapsulacja
Przegląd poziomów dostępuMetody pobierające i ustawiająceUkrywanie informacjiSłowo kluczowe finalPodsumowanie — menedżer kont bankowych5Polimorfizm
Podstawy przeciążania metodPrzesłanianie metod (w czasie wykonywania)Rzutowanie w górę i w dółOperator instanceofKlasy i metody abstrakcyjnePowtórka — kalkulator figur8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieAgregacja a kompozycjaKlasy wewnętrzne, zagnieżdżone i anonimoweEnumy i metody enumówRekordy (Java 16+)Klasy zapieczętowane (Java 17+)11Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec BuilderWzorzec ObserverWzorzec Strategy3Właściwości klas i składowe statyczne
Zmienne instancji a zmienne statyczneMetody statyczneBloki statyczneStałe (static final)Powtórka – Counter i Utility6Interfejsy i klasy abstrakcyjne
Wprowadzenie do interfejsówImplementowanie interfejsówImplementacja wielu interfejsówMetody domyślne i statyczne w interfejsieKlasy abstrakcyjne a interfejsyInterfejsy funkcyjnePodsumowanie — system płatnościPoćwicz samodzielnie: Kompilator Java online