Паттерн Try With Resources
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 62 из 87.
При работе с такими ресурсами, как файловые потоки или подключения к базам данных, вы всегда должны закрывать их по завершении работы — в противном случае вы рискуете столкнуться с утечками памяти. Традиционный подход использует блок finally, но он многословен и подвержен ошибкам.
Оператор Java try-with-resources автоматически закрывает ресурсы по завершении блока. Любой класс, реализующий интерфейс AutoCloseable, может использоваться с этим синтаксисом:
// Традиционный подход — многословный и рискованный
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} finally {
if (reader != null) {
reader.close(); // Также может вызвать исключение!
}
}
// Try-with-resources — чистый и безопасный
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
} // Автоматически закрывается здесьВы можете управлять несколькими ресурсами, разделяя их точкой с запятой. Они закрываются в порядке, обратном порядку их объявления:
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
// Используйте оба ресурса
} // br закрывается первым, затем frЧтобы создать свой собственный автоматически закрываемый класс, реализуйте интерфейс AutoCloseable и его единственный метод close():
public class DatabaseConnection implements AutoCloseable {
public DatabaseConnection() {
System.out.println("Connection opened");
}
@Override
public void close() {
System.out.println("Connection closed");
}
}Этот паттерн гарантирует, что ресурсы всегда будут освобождены должным образом, даже если во время обработки возникнут исключения.
Задание
ЛегкоДавайте создадим систему управления ресурсами, которая демонстрирует мощь try-with-resources! Вы создадите пользовательские автозакрываемые классы, имитирующие управление соединениями и сессиями, гарантируя, что они всегда будут правильно очищены.
Вы организуете свой код в трех файлах:
Connection.java: Создайте класс, имитирующий соединение с базой данных. Ваш классConnectionдолжен реализовывать интерфейсAutoCloseable. Ему требуется приватное поле для имени соединения (String), конструктор, который принимает имя и выводит[name] connection opened, методquery(String sql), который выводитExecuting on [name]: [sql], и обязательный методclose(), который выводит[name] connection closed.Session.java: Создайте еще один автозакрываемый класс, имитирующий пользовательскую сессию. Ваш классSessionтакже должен реализовыватьAutoCloseable. Включите приватное поле для имени пользователя (String), конструктор, который принимает имя пользователя и выводитSession started for [username], методperformAction(String action), который выводит[username] performed: [action], и методclose(), который выводитSession ended for [username].Main.java: Объедините вашу систему управления ресурсами! Вы получите три входных значения: имя соединения, имя пользователя и действие для выполнения.Сначала продемонстрируйте управление одиночным ресурсом. Выведите
=== Single Resource ===, затем используйте try-with-resources для созданияConnectionс заданным именем. Внутри блока try вызовитеquery("SELECT * FROM users"). Соединение должно автоматически закрыться по завершении блока.Затем продемонстрируйте работу с несколькими ресурсами. Выведите пустую строку, а затем
=== Multiple Resources ===. Используйте try-with-resources одновременно сConnection(используя то же имя) иSession(используя имя пользователя), объявленными в таком порядке через точку с запятой. Внутри блока try сначала вызовитеquery("INSERT INTO logs")у соединения, а затем вызовитеperformActionс входным действием у сессии. Посмотрите, как ресурсы закрываются в обратном порядке!
Вы получите три входных значения по порядку: имя соединения (String), имя пользователя (String) и действие (String).
Обратите внимание, как try-with-resources избавляет от необходимости явных вызовов close и блоков finally. Ресурсы гарантированно закроются, даже если возникнут исключения, а несколько ресурсов закрываются в порядке, обратном их объявлению!
Шпаргалка
Оператор try-with-resources автоматически закрывает ресурсы по завершении блока. Можно использовать любой класс, реализующий интерфейс AutoCloseable:
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
} // Автоматически закрывается здесьМожно управлять несколькими ресурсами, разделяя их точкой с запятой. Они закрываются в порядке, обратном порядку их объявления:
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
// Использование обоих ресурсов
} // сначала закрывается br, затем frЧтобы создать собственный класс с поддержкой автоматического закрытия, реализуйте интерфейс AutoCloseable и его метод close():
public class DatabaseConnection implements AutoCloseable {
public DatabaseConnection() {
System.out.println("Connection opened");
}
@Override
public void close() {
System.out.println("Connection closed");
}
}Попробуйте сами
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: Выведите заголовок
// TODO: Используйте try-with-resources для создания Connection
// TODO: Внутри блока try вызовите query("SELECT * FROM users")
// === Multiple Resources ===
// TODO: Выведите пустую строку и заголовок
// TODO: Используйте try-with-resources одновременно с Connection и Session
// TODO: Внутри блока try:
// - Вызовите query("INSERT INTO logs") у объекта connection
// - Вызовите performAction с входным действием action у объекта session
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка10Обработка исключений в ООП
Иерархия классов исключенийПользовательские исключенияПроверяемые и непроверяемые ошибкиПаттерн Try With ResourcesПовторение — Validated User2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»