try-with-resources Java
У Java є звичайний try, а є try-with-resources.
На перший погляд вони виглядають майже однаково, і через це легко заплутатися. Але різниця дуже проста: у try-with-resources після слова try є круглі дужки ().
Саме в ці дужки ми кладемо ресурс, який Java має автоматично закрити після використання.
Звичайний try
Звичайний try-catch використовується, коли у нас є код, який може впасти з помилкою:
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Помилка ділення");
} Тут усе просто:
- код у
tryпробує виконатися; - якщо сталася помилка, вона потрапляє в
catch; - у
catchми її обробляємо.
Тобто звичайний try — це про обробку помилок.
То що не так із ресурсами?
У Java є обʼєкти, які після використання треба закривати. Наприклад:
BufferedReader
FileInputStream
Connection
PreparedStatement
ResultSet
Socket
Scanner Такі обʼєкти зазвичай мають метод:
close() Проблема в тому, що якщо ми відкрили файл або підключення до бази даних і не закрили його, ресурс може залишитися висіти відкритим.
Наприклад:
try {
BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
} На вигляд усе нормально. Але тут є нюанс: reader не закривається автоматично.
Тобто Java не викличе сама:
reader.close(); Раніше для цього часто використовували finally:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("data.txt"));
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} Працює, але виглядає страшнувато.
Багато коду тільки заради того, щоб нормально закрити ресурс.
try-with-resources
Починаючи з Java 7, можна писати простіше:
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
} Ось ця частина і є головна:
try (BufferedReader reader = ...) Ресурс створюється не всередині { }, а в круглих дужках після try.
І це означає:
Java сама закриє цей ресурс після завершення блоку
try.
Причому неважливо, як саме завершився блок:
- успішно;
- з помилкою;
- через
return; - через exception.
Ресурс усе одно буде закритий.
Головна різниця в коді
Звичайний try:
try {
BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
reader.readLine();
} try-with-resources:
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
reader.readLine();
} Візуально різниця маленька:
try { проти:
try (...) { Але логічно різниця велика.
У першому випадку ресурс сам не закриється.
У другому випадку Java автоматично викличе close().
Що можна класти в дужки?
У дужки після try можна покласти обʼєкти, які реалізують AutoCloseable або Closeable.
Наприклад:
try (Scanner scanner = new Scanner(System.in)) {
String name = scanner.nextLine();
System.out.println(name);
} Або кілька ресурсів одразу:
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM users");
ResultSet resultSet = statement.executeQuery()
) {
while (resultSet.next()) {
System.out.println(resultSet.getString("name"));
}
} Java закриє ресурси автоматично у зворотному порядку:
resultSet
statement
connection Це логічно, бо спочатку треба закрити те, що залежить від іншого ресурсу.
Просте правило
Якщо треба просто перехопити помилку — використовуємо звичайний try-catch.
try {
// небезпечний код
} catch (Exception e) {
// обробка помилки
} Якщо працюємо з ресурсом, який треба закрити, — використовуємо try-with-resources.
try (Resource resource = new Resource()) {
// робота з ресурсом
} Коротко
try { ... } — просто виконує код і дозволяє обробити помилку.
try (...) { ... } — виконує код і автоматично закриває ресурс із круглих дужок.
Тобто вся візуальна різниця — це круглі дужки після try.
А вся практична користь — у тому, що Java сама викликає close().
Comments
Please ensure Giscus is configured with your correct Repository ID and Category ID at giscus.app to enable comments.