— Привіт, Аміго!

Давай ще раз обговоримо метод finalize().

Якщо ти пам'ятаєш, finalize() – це спеціальний метод, який викликається в об'єкта перед тим, як
збирач сміття його знищить.

Основна мета цього методу – звільнити зовнішні не-Java ресурси, що використовуються: закрити файли, потоки введення-виведення тощо.

На жаль, цей метод не виправдовує покладених на нього надій. Java-машина може відкладати знищення об'єкта, як і виклик методу finalize скільки завгодно. Більше того, вона взагалі не гарантує, що цей метод буде викликано. У багатьох ситуаціях заради «оптимізації» він не викликається.

Наведу тобі дві цитати:

У Джошуа Блоха добре написано про цей метод: link
Короткий опис:

  1. finalize() можна використовувати лише у двох випадках:
    1. Перевірка/підчищення ресурсів з логуванням.
    2. Під час роботи з нативним кодом, який не є критичним до витоку ресурсів.
  2. finalize() сповільнює роботу GC з очищення об'єкта у 430 разів
  3. finalize() може бути не викликаний
Якщо я на співбесіді скажу, що finalize — це шкідлива і небезпечна милиця, яка своїм існуванням збиває з пантелику, то буду правий?

— М-да, це "втішно".

— На заміну методу finalize у Java 7 з'явилася нова конструкція. Називається вона – try-with-resources. Це не зовсім заміна finalize – скоріше альтернативний підхід.

— Як try-catch, тільки з ресурсами?

— Майже як try-catch. Справа в тому, що на відміну від методу finalize(), блок finally з конструкції try-catch-finally викликається завжди. Цим і користувалися програмісти, коли потрібно було гарантовано звільнити ресурси, закрити потоки тощо.
Приклад:

InputStream is = null;
try
{
 is = new FileInputStream("c:/file.txt");
 is.read();
}
finally
{
 if (is != null)
 is.close();
}

Незалежно від того, чи нормально відпрацював блок try, чи там виник виняток, блок finally буде викликаний завжди, і там можна буде звільнити зайняті ресурси.

Тому в Java 7 цей підхід вирішили зробити офіційним, і ось що з цього вийшло:

try(InputStream is = new FileInputStream("c:/file.txt"))
{
 is.read();
}

Це спеціальна конструкція try, яка називається try-with-resources (так само як і другий for для колекцій називається foreach).

Зверни увагу – після try йдуть круглі дужки, де оголошуються змінні та створюються об'єкти. Ці об'єкти можна використовувати всередині блоку try, позначеного дужками {}. Коли виконання команд блоку try закінчиться, незалежно від того нормально він закінчився або був виняток, для об'єкта, створеного всередині круглих дужок (), буде викликаний метод close();

— Такий запис набагато компактніший, ніж попередній. Зрозуміти його б ще.

— Все не так складно, як ти думаєш.

— А я можу вказувати у круглих дужках об'єкти своїх класів?

— Звичайно, інакше від цих дужок було б мало користі.

— А якщо мені потрібно викликати інший метод при виході із блоку try, де мені його вказати?

— Тут все трохи вишуканіше. У Java 7 з'явився такий інтерфейс:

public interface AutoCloseable
{
 void close() throws Exception;
}

Ти можеш успадкувати свій клас від такого інтерфейсу. І тоді його об'єкти можна використовувати всередині try-with-resources. Тільки об'єкти такого типу можна використовувати всередині круглих дужок try-with-resources для автоматичного закриття.

— Тобто мені потрібно перевизначити метод close і написати в ньому код «очищення» мого об'єкта, а вказати інший метод не можна?

— Ага. Проте можна вказувати кілька об'єктів, розділивши їх крапкою з комою:

try(
InputStream is = new FileInputStream("c:/file.txt");
OutputStream os = new FileOutputStream("c:/output.txt")
)
{
 is.read();
 os.write();
}

— Вже краще, але не так круто, як я сподівався.

— Все не так погано, ти звикнеш. З часом.