Я прочитал множество вопросов новичков по Java о finalize() и нахожу меня немного сбивающим с толку тем, что никто на самом деле не дал понять, что finalize () - ненадежный способ очистки ресурсов. Я видел, как кто-то заметил, что они используют его для очистки подключений, что действительно пугает, поскольку единственный способ приблизиться к гарантии закрытия подключения - это наконец реализовать try (catch).
Я не учился в CS, но я профессионально программировал на Java уже почти десять лет, и я никогда не видел, чтобы кто-нибудь внедрил finalize() в производственную систему. Это все еще не означает, что он не имеет своего применения или что люди, с которыми я работал, делали это правильно.
Итак, мой вопрос: какие существуют варианты использования для реализации finalize(), которые нельзя обрабатывать более надежно с помощью другого процесса или синтаксиса в языке?
Пожалуйста, предоставьте конкретные сценарии или свой опыт, простого повторения учебника Java или завершения предполагаемого использования недостаточно, поскольку это не цель этого вопроса.
Код большинства приложений и библиотек никогда не будет использовать finalize(). Однако код библиотеки платформы, такой как SocketInputStream, который управляет собственными ресурсами от имени вызывающего, делает это, чтобы попытаться минимизировать риск утечки ресурсов (или использует эквивалентные механизмы, такие как PhantomReference, которые были добавлены позже). Таким образом, экосистеме они нужны. , хотя 99,9999% разработчиков никогда его не напишут.
finalize is now deprecated, as of Java 9. See the Question, Почему метод finalize () устарел в Java 9?.




Я профессионально занимаюсь Java с 1998 года и никогда не внедрял finalize(). Ни разу.
Как мне тогда уничтожить объект публичного класса? Это вызывает проблему в ADF. В основном предполагается перезагрузка страницы (получение свежих данных из API), но при этом используется старый объект и отображаются результаты.
@ InfantPro'Aravind 'вызов finalize не удаляет объект. Это реализуемый вами метод, который JVM может выбрать для вызова, если и когда она собирает ваш объект мусором.
@PaulTomblin, спасибо за эту деталь. Есть ли предложения по обновлению страницы в ADF?
@ InfantPro'Aravind 'Понятия не имею, никогда не использовал АПД.
При написании кода, который будет использоваться другими разработчиками, требующим вызова какого-либо метода «очистки» для освобождения ресурсов. Иногда другие разработчики забывают вызвать ваш метод очистки (или закрытия, или уничтожения, или чего-то еще). Чтобы избежать возможных утечек ресурсов, вы можете проверить метод finalize, чтобы убедиться, что метод был вызван, и если это не так, вы можете вызвать его самостоятельно.
Многие драйверы баз данных делают это в своих реализациях Statement и Connection, чтобы обеспечить некоторую защиту от разработчиков, которые забывают их закрыть.
Вы не должны зависеть от finalize (), чтобы очистить ваши ресурсы за вас. finalize () не будет работать до тех пор, пока класс не будет собран сборщиком мусора. Гораздо лучше явно освободить ресурсы, когда вы закончите их использовать.
Вы можете использовать его в качестве упора для объекта, содержащего внешний ресурс (сокет, файл и т. д.). Реализуйте метод close() и задокументируйте, что он должен быть вызван.
Внедрите finalize() для обработки close(), если вы обнаружите, что это не было сделано. Может быть, что-то сброшено на stderr, чтобы указать, что вы убираетесь после глючного звонящего.
Это обеспечивает дополнительную безопасность в исключительной ситуации / ситуации с ошибками. Не каждый вызывающий абонент будет каждый раз выполнять правильные действия с try {} finally {}. К сожалению, но верно в большинстве случаев.
Я согласен, что это редко нужно. И, как отмечают комментаторы, это связано с накладными расходами сборщика мусора. Используйте только в том случае, если вам нужна безопасность с «поясом и подтяжками» в долго работающем приложении.
Я вижу, что с Java 9 Object.finalize() устарел! Они указывают нам на альтернативы java.lang.ref.Cleaner и java.lang.ref.PhantomReference.
Думаю, я обычно хорошо документирую, а затем кричу на людей, когда они не читают документацию. Думаю, это тоже поможет. ухмылка
Просто убедитесь, что finalize () никогда не генерирует исключение, иначе сборщик мусора не продолжит очистку этого объекта, и вы получите утечку памяти.
Вызов Finalize не гарантируется, поэтому не рассчитывайте, что он освободит ресурс.
Помните, что finalize также снижает производительность из-за того, что для очистки объекта требуется более одного GC!
skaffman - я в это не верю (за исключением некоторой глючной реализации JVM). Из документации Object.finalize () javadoc: Если методом finalize генерируется неперехваченное исключение, исключение игнорируется и завершение этого объекта завершается.
Ваше предложение может скрывать баги людей (не звонить близко) на долгое время. Я бы не рекомендовал это делать.
Почему бы просто не поместить утверждение в finalize, проверяя, что объект готов к удалению, т.е. «закрыт» вместо записи в журнал?
Если вам нужна безопасность «ремня и подтяжек» для поддержания работоспособности важной системы, я не хочу, чтобы вылетела ошибка AssertionError. Я хотел бы максимизировать вероятность того, что система продолжит работать, выполняя очистку, оставляя информацию в журнале, чтобы я мог понять, что что-то не так.
Finalize снижает производительность сборки мусора, поскольку сборщик мусора должен дважды проверить, был ли объект собран.
На самом деле я использовал finalize именно по этой причине. Я унаследовал код, он был очень глючным и имел тенденцию оставлять соединения с базой данных открытыми. Мы изменили соединения, чтобы они содержали данные о том, когда и где они были созданы, а затем реализовали finalize для регистрации этой информации, если соединение не было закрыто должным образом. Это оказалось большим подспорьем в отслеживании незамкнутых соединений.
Из документа Java об Object.finalize () - «Любое исключение, созданное методом finalize, вызывает остановку завершения этого объекта, но в противном случае игнорируется». Таким образом, исключения не заставят объект оставаться в памяти
@brainimus Может быть даже вариантом отладки в пуле соединений JDBC.
Наконец, устарел, лучше использовать какой-то шаблон субъект-наблюдатель, в котором компоненты вашего приложения могут регистрироваться на «ловушке выключения» и выполнять очистку без использования finalize() (см. Ответ SteveJessop). Немного ОТ: никогда и никогда вызывает finalize() самостоятельно! Это будет иметь побочные эффекты, помимо неизвестных (сбои, сбои, прерывания JVM). В случае сомнений избегайте этого любой ценой.
@Roland finalize() - это просто метод. Сам вызов его не имеет никаких других эффектов, кроме выполнения содержащегося в нем кода. Это семантически неверно и поэтому приведет к кошмару обслуживания, но нет причин, по которым он должен вызывать сбой JVM.
@VladGudim нет смысла помещать утверждение вместо оператора регистрации в finalize(), поскольку единственная цель инструкции assert - вызвать какое-то ведение журнала, просто косвенно через AssertionError, который будет брошен и, надеюсь, зарегистрирован. В случае finalize() этого не произойдет, поскольку все выданные исключения просто игнорируются.
@Holger, спасибо, я знаю, что нельзя вызывать finalize() вручную, поскольку это делает сборщик мусора (насколько я правильно помню).
@Roland ну да, вы не должны вызывать его вручную, или на самом деле вы не должны его доработать вообще. Но побочные эффекты от его применения не так уж драматичны.
Единственный раз, когда я использовал finalize в производственном коде, было реализовать проверку того, что ресурсы данного объекта были очищены, а если нет, то записать очень громкое сообщение. На самом деле он не пытался сделать это сам, он просто много кричал, если это не было сделано должным образом. Оказалось весьма полезным.
Будьте осторожны с тем, что вы делаете в finalize(). Особенно, если вы используете его для таких вещей, как вызов close (), чтобы убедиться, что ресурсы очищены. Мы столкнулись с несколькими ситуациями, когда у нас были библиотеки JNI, связанные с работающим java-кодом, и в любых обстоятельствах, когда мы использовали finalize () для вызова методов JNI, мы получали очень серьезное повреждение кучи java. Повреждение не было вызвано самим базовым кодом JNI, все следы памяти были в порядке в собственных библиотеках. Дело в том, что мы вообще вызывали методы JNI из finalize ().
Это было с JDK 1.5, который до сих пор широко используется.
Мы не узнаем, что что-то пошло не так, гораздо позже, но в конечном итоге виновником всегда был метод finalize (), использующий вызовы JNI.
Как вам удалось освободить память, выделенную в JNI?
finalize() - это подсказка JVM, что было бы неплохо выполнить ваш код в неопределенное время. Это хорошо, когда вы хотите, чтобы код по загадочным причинам не запускался.
Делать что-либо существенное в финализаторах (в основном что угодно, кроме ведения журнала) также хорошо в трех ситуациях:
Если вы думаете, что вам нужен finalize (), иногда действительно нужно фантомная ссылка (который в приведенном примере может содержать жесткую ссылку на соединение, используемое его референдумом, и закрывать его после того, как фантомная ссылка была поставлена в очередь). Это также имеет свойство, что он может загадочным образом никогда не запускаться, но, по крайней мере, он не может вызывать методы или воскрешать завершенные объекты. Так что это как раз подходит для ситуаций, когда вам совершенно не нужно полностью закрывать это соединение, но вы очень этого хотите, а клиенты вашего класса не могут или не будут вызывать закрытие (что на самом деле достаточно справедливо - какой смысл вообще иметь сборщик мусора, если вы разрабатываете интерфейсы, которые требовать перед сборкой выполняет определенное действие? Это просто возвращает нас во времена malloc / free.)
В других случаях вам нужен ресурс, который, как вы думаете, вам удастся стать более надежным. Например, зачем вам закрывать это соединение? В конечном итоге он должен быть основан на каком-то вводе-выводе, предоставляемом системой (сокет, файл, что угодно), так почему вы не можете полагаться на систему, чтобы закрыть его для вас, когда предоставлен самый низкий уровень ресурсов? Если сервер на другом конце абсолютно требует, чтобы вы полностью закрыли соединение, а не просто отключили сокет, то что произойдет, если кто-то споткнется о кабель питания машины, на которой работает ваш код, или промежуточная сеть отключится?
Отказ от ответственности: в прошлом я работал над реализацией JVM. Ненавижу финализаторы.
Голосование за справедливость крайнего сарказма.
Это не отвечает на вопрос; он просто говорит обо всех недостатках finalize() без объяснения причин, по которым кто-то действительно хотел бы его использовать.
Были ли финализаторы и фантомные ссылки частью исходной спецификации JVM? Если бы у кого-то были фантомные ссылки и если бы была определенная системой очередь уведомлений о фантомных ссылках, которая уведомляла бы любые объекты, которые были GC'ed на максимально удобной основе, их (вместе с WeakReference) было бы достаточно, чтобы делать почти все код должен делать с finalize [воскресение может быть невозможно, но я не уверен, что это будет плохо].
@supercat: фантомные ссылки (если на то пошло, все ссылки) были введены в Java 2
@SteveJessop: Я полагаю, вы имеете в виду все типы с Reference в названии. Базовые ссылки на объекты настолько фундаментальны, что я не могу представить, чтобы их не было на Java с самого начала. Я предполагаю, что финализаторы были на Java 1?
@supercat: извините, да, под "ссылками" я имел в виду java.lang.ref.Reference и его подклассы. В Java 1 были переменные :-) И да, были и финализаторы.
@SteveJessop: Java принесла в широкое распространение как хорошие, так и плохие идеи. В основном я имею дело с .net, но мне интересно посмотреть, как он соотносится с Java. Жаль, что ни один из них не предоставил первоклассную поддержку для детерминированной очистки, поскольку 99% очистки объекта можно легко выполнить детерминированно, а значительная часть может быть обработана только детерминированно. Кроме того, 99% трудностей, связанных с «глубокими» и «мелкими» операциями, можно было бы разрешить, если бы существовало лингвистическое различие между ссылками, которые инкапсулируют ИДЕНТИЧНОСТЬ объекта и его СОСТОЯНИЕ.
@supercat: Ну, C# "using" и Java "try-with-resources" действительно обеспечивают детерминированную очистку (как, конечно, try / finally). Они просто не выполняют детерминированную очистку распределения памяти. В обоих случаях это, возможно, просто крайнее преувеличение того факта, что C скрывает детали malloc - в C нет гарантия, что, если вы освободите некоторую память, вы можете немедленно выделить равный объем памяти. Проблема удобства использования finalize() заключается в том, что он усложняет сборку мусора с точки зрения пользователя, тогда как сложность «должна» заключаться только в реализации.
@SteveJessop: Недетерминированное восстановление памяти не является проблемой, поскольку то, является ли часть памяти «свободной», имеет значение только в том случае, если для чего-то будет использоваться немедленный. Проблема возникает с объектами, которые просят другие объекты изменить состояние от их имени до дальнейшего уведомления (особенно когда объекты предоставляют объектам эксклюзивный доступ к ресурсам). Это очень распространенный шаблон, с которым finalize очень плохо справляется. Использование .Net и запоздалое появление Java "try-with-resources" полезны в некоторых сценариях, но есть распространенный сценарий, когда они действительно терпят неудачу:
@SteveJessop: если конструктор базового класса просит другие сущности изменить свое состояние от имени строящегося объекта (очень распространенный шаблон), но инициализатор поля производного класса выдает исключение, частично созданный объект должен немедленно очистить после себя (т. е. уведомить эти внешние объекты, что их услуги больше не требуются), но ни Java, ни .NET не предлагают какой-либо даже удаленно-чистый шаблон, с помощью которого это может происходить. В самом деле, они, кажется, изо всех сил стараются усложнить ссылку на объект, нуждающийся в очистке, чтобы добраться до кода очистки.
Хммм, однажды я использовал его для очистки объектов, которые не возвращались в существующий пул.
Их часто передавали, поэтому было невозможно сказать, когда их можно будет безопасно вернуть в бассейн. Проблема заключалась в том, что это приводило к огромному штрафу за сборку мусора, который был намного больше, чем любая экономия от объединения объектов. Он находился в производстве около месяца, прежде чем я вырвал весь пул, сделал все динамичным и покончил с этим.
Принятый ответ хорош, я просто хотел добавить, что теперь есть способ получить функциональность финализации, фактически не используя ее.
Посмотрите на «Референсные» классы. Слабая ссылка, фантомная ссылка и мягкая ссылка.
Вы можете использовать их для сохранения ссылки на все ваши объекты, но эта ссылка ОДНАКО не остановит сборщик мусора. Самое интересное в том, что вы можете заставить его вызывать метод, когда он будет удален, и этот метод может быть вызван гарантированный.
Что касается доработки: Я использовал finalize один раз, чтобы понять, какие объекты были освобождены. Вы можете поиграть в некоторые изящные игры со статикой, подсчетом ссылок и т. д. - но это было только для анализа, но следите за кодом, подобным этому (не только в финальной версии, но именно там вы, скорее всего, его увидите):
public void finalize() {
ref1 = null;
ref2 = null;
othercrap = null;
}
Это знак того, что кто-то не знал, что делал. Такая «уборка» практически не нужна. Когда класс GC'd, это делается автоматически.
Если вы обнаружите такой код в финальной версии, это гарантирует, что человек, который его написал, запутался.
Если это где-то еще, возможно, код является допустимым патчем для плохой модели (класс остается в течение длительного времени, и по какой-то причине вещи, на которые он ссылается, должны были быть вручную освобождены до того, как объект будет GC'd). Обычно это происходит потому, что кто-то забыл удалить слушателя или что-то в этом роде и не может понять, почему их объект не хранится в GC, поэтому они просто удаляют то, на что он ссылается, пожимают плечами и уходят.
Его никогда не следует использовать для очистки «Быстрее».
Я думаю, что фантомные ссылки - лучший способ отслеживать, какие объекты освобождаются.
голосование за лучшее объяснение "слабой ссылки", которое я когда-либо слышал.
Мне жаль, что мне потребовалось столько лет, чтобы прочитать это, но это действительно хорошее дополнение к ответам.
Простое правило: никогда не используйте финализаторы.
Самого факта, что у объекта есть финализатор (независимо от того, какой код он выполняет), достаточно, чтобы вызвать значительные накладные расходы на сборку мусора.
Из статья Брайана Гетца:
Objects with finalizers (those that have a non-trivial finalize() method) have significant overhead compared to objects without finalizers, and should be used sparingly. Finalizeable objects are both slower to allocate and slower to collect. At allocation time, the JVM must register any finalizeable objects with the garbage collector, and (at least in the HotSpot JVM implementation) finalizeable objects must follow a slower allocation path than most other objects. Similarly, finalizeable objects are slower to collect, too. It takes at least two garbage collection cycles (in the best case) before a finalizeable object can be reclaimed, and the garbage collector has to do extra work to invoke the finalizer. The result is more time spent allocating and collecting objects and more pressure on the garbage collector, because the memory used by unreachable finalizeable objects is retained longer. Combine that with the fact that finalizers are not guaranteed to run in any predictable timeframe, or even at all, and you can see that there are relatively few situations for which finalization is the right tool to use.
Чтобы выделить точку в приведенных выше ответах: финализаторы будут выполняться в единственном потоке GC. Я слышал о крупной демонстрации Sun, в которой разработчики добавили небольшой сон некоторым финализаторам и намеренно поставили на колени модную 3D-демонстрацию.
Лучше избегать, за исключением, возможно, диагностики test-env.
В «Мышлении Эккеля на Java» есть хороший раздел по этому поводу.
Я не уверен, что вы можете с этим поделать, но ...
itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41
Итак, я полагаю, что Sun нашла случаи немного, в которых (они думают) его следует использовать.
Думаю, это также вопрос: «Всегда ли будет прав разработчик Sun»?
Но сколько из этих применений просто реализует или тестирует поддержку finalize, а не использует ее на самом деле?
Пользуюсь виндой. Как бы вы сделали то же самое в Windows?
@damryfbfnetsi: попробуйте установить ack (Beyondgrep.com) с помощью шоколадный.org/packages/ack. Или воспользуйтесь простой функцией поиска в файлах в $FAVORITE_IDE.
finalize() может быть полезен для обнаружения утечек ресурсов. Если ресурс должен быть закрыт, но не работает, запишите факт, что он не был закрыт, в файл журнала и закройте его. Таким образом вы устраните утечку ресурсов и дадите себе возможность узнать, что это произошло, чтобы вы могли ее исправить.
Я программирую на Java с 1.0 alpha 3 (1995), и мне еще предстоит переопределить finalize для чего-либо ...
class MyObject {
Test main;
public MyObject(Test t) {
main = t;
}
protected void finalize() {
main.ref = this; // let instance become reachable again
System.out.println("This is finalize"); //test finalize run only once
}
}
class Test {
MyObject ref;
public static void main(String[] args) {
Test test = new Test();
test.ref = new MyObject(test);
test.ref = null; //MyObject become unreachable,finalize will be invoked
System.gc();
if (test.ref != null) System.out.println("MyObject still alive!");
}
}
====================================
результат:
This is finalize
MyObject still alive!
=====================================
Таким образом, вы можете сделать недоступный экземпляр доступным в методе finalize.
Почему-то этот код наводит на мысль о фильмах про зомби. Вы собираете свой объект, а затем он снова встает ...
выше хорошие коды. Мне только что было интересно, как сделать объект снова доступным.
нет, выше неверные коды. это пример того, почему финализация - это плохо.
Помните, что вызов System.gc(); не является гарантией того, что сборщик мусора действительно запустится. Это полное усмотрение GC очищать кучу (может быть, все еще достаточно свободной кучи, может быть, не слишком фрагментировано, ...). Так что это всего лишь скромная просьба программиста «пожалуйста, не могли бы вы выслушать меня и бежать?» а не команду «беги, как я говорю!». Извините за использование языковых слов, но он говорит именно так, как работает GC JVM.
Обновлено: Хорошо, это действительно не работает. Я реализовал его и подумал, что если иногда он выходит из строя, это нормально для меня, но он даже не вызвал метод finalize ни разу.
Я не профессиональный программист, но в моей программе есть случай, который я считаю хорошим примером использования finalize (), то есть кеш, который записывает свое содержимое на диск до его уничтожения. Поскольку нет необходимости, чтобы он выполнялся каждый раз при уничтожении, это только ускоряет мою программу, я надеюсь, что я не ошибся.
@Override
public void finalize()
{
try {saveCache();} catch (Exception e) {e.printStackTrace();}
}
public void saveCache() throws FileNotFoundException, IOException
{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
out.writeObject(cache);
}
Я думаю, что кеш (того типа, который вы бы сбросили на диск) является хорошим примером. И даже если доработка не называется, не парься.
Это может быть удобно для удаления вещей, которые были добавлены в глобальное / статическое место (из-за необходимости) и должны быть удалены при удалении объекта. Например:
private void addGlobalClickListener() {
weakAwtEventListener = new WeakAWTEventListener(this);
Toolkit.getDefaultToolkit().addAWTEventListener(weakAwtEventListener, AWTEvent.MOUSE_EVENT_MASK);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (weakAwtEventListener != null) {
Toolkit.getDefaultToolkit().removeAWTEventListener(weakAwtEventListener);
}
}
Это требует дополнительных усилий, поскольку, когда у слушателя есть сильная ссылка на экземпляр this, переданная ему в конструкторе, этот экземпляр никогда не станет недоступным, следовательно, finalize() никогда не очистится. Если же, с другой стороны, слушатель имеет слабую ссылку на этот объект, как следует из названия, эта конструкция рискует быть очищенной время от времени, когда этого не следует делать. Жизненные циклы объектов - не лучший инструмент для реализации семантики приложения.
iirc - вы можете использовать метод finalize как средство реализации механизма объединения для дорогостоящих ресурсов - поэтому они также не получают GC.
В принятом ответе указывается, что можно закрыть ресурс во время финализации.
Однако этот ответ показывает, что, по крайней мере, в java8 с JIT-компилятором вы сталкиваетесь с неожиданными проблемами, когда иногда финализатор вызывается даже до того, как вы закончите чтение из потока, поддерживаемого вашим объектом.
Так что даже в этой ситуации вызов finalize будет рекомендован нет.
Это сработает, если операция сделана потокобезопасной, что является обязательным, поскольку финализаторы могут вызываться произвольными потоками. Поскольку правильно реализованная потокобезопасность подразумевает, что не только операция закрытия, но и операции, использующие ресурс, должны синхронизироваться с одним и тем же объектом или блокировкой, между использованием и операцией закрытия будет возникать связь «происходит раньше», что также предотвращает слишком раннее доработка. Но, конечно, по высокой цене за все время использования…
Лично я почти никогда не использовал finalize(), за исключением одного редкого случая: я создал собственную коллекцию универсального типа и написал собственный метод finalize(), который выполняет следующие действия:
public void finalize() throws Throwable {
super.finalize();
if (destructiveFinalize) {
T item;
for (int i = 0, l = length(); i < l; i++) {
item = get(i);
if (item == null) {
continue;
}
if (item instanceof Window) {
((Window) get(i)).dispose();
}
if (item instanceof CompleteObject) {
((CompleteObject) get(i)).finalize();
}
set(i, null);
}
}
}
(CompleteObject is an interface I made that lets you specify that you've implemented rarely-implemented Object methods like #finalize(), #hashCode(), and #clone())
Таким образом, используя родственный метод #setDestructivelyFinalizes(boolean), программа, использующая мою коллекцию, может (помочь) гарантировать, что уничтожение ссылки на эту коллекцию также уничтожит ссылки на ее содержимое и удалит все окна, которые могут непреднамеренно поддерживать работу JVM. Я подумал также о том, чтобы остановить любые потоки, но это открыло новую банку червей.
Вызов finalize() в ваших экземплярах CompleteObject, как вы делаете в приведенном выше коде, означает, что он может быть вызван дважды, поскольку JVM все еще может вызывать finalize(), когда эти объекты фактически становятся недоступными, что из-за логики завершения может быть до методом finalize() из вашей специальной коллекции вызывается или даже одновременно. Поскольку я не вижу никаких мер по обеспечению безопасности потоков в вашем методе, вы, кажется, не знаете об этом ...
Ресурсы (файл, сокет, поток и т. д.) Необходимо закрыть, как только мы закончим с ними. Обычно у них есть метод close(), который мы обычно вызываем в разделе finally инструкций try-catch. Иногда finalize() также может использоваться несколькими разработчиками, но IMO не подходит, поскольку нет гарантии, что finalize будет вызываться всегда.
В Java 7 есть оператор попробовать с ресурсами, который можно использовать как:
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
// Processing and other logic here.
} catch (Exception e) {
// log exception
} finally {
// Just in case we need to do some stuff here.
}
В приведенном выше примере try-with-resource автоматически закроет ресурс BufferedReader, вызвав метод close(). Если мы хотим, мы также можем реализовать Закрывающийся в наших собственных классах и использовать его аналогичным образом. ИМО это кажется более изящным и простым для понимания.
В качестве примечания:
An object that overrides finalize() is treated specially by the garbage collector. Usually, an object is immediately destroyed during the collection cycle after the object is no longer in scope. However, finalizable objects are instead moved to a queue, where separate finalization threads will drain the queue and run the finalize() method on each object. Once the finalize() method terminates, the object will at last be ready for garbage collection in the next cycle.
Источник: finalize () устарел на java-9
HI метод finalize () очень хорошо объяснен здесь howtodoinjava.com/2012/10/31/…