2012-05-01 4 views
0

У меня есть некоторые вопросы относительно завершения Java. Например, у меня есть один класс FileHelper, и этот класс связан с чтением файла, записью файла и т. Д. Теперь мой вопрос: у меня есть один метод writeFile() в классе FileHelper. Теперь, если я хочу закрыть этот файл , следует ли переопределить метод finalize() и закрыть файл или закрыть файл внутри метода writeFile() сам? Каков правильный способ? Я объявил переменную File как переменную-член. Если переопределение является плохой идеей, то почему мы хотим переопределить метод finalize()? какой сценарий? Я прочитал много статей, где они говорят, чтобы закрыть системные ресурсы, такие как файл, шрифт и т. Д.java finalization сомнения

ответ

3

Лучшей практикой является как можно скорее закрыть файл. Если у вас есть статический метод в FileHelper (при условии, что ваш помощник является связкой статических «вспомогательных» методов) Я бы закрыть файл внутри

static void writeFile(String fileName, String text) { // Exception 
// Open file here 
// write text 
// close it 
} 

Целью наиважнейшей финализации является релизом неуправляемых ресурсов, например, файлы на случай, если кто-то забудет это сделать. Если кто-то использует ваш помощник этот путь

FileHelper fileHelper = new FileHelper(file); 
fileHelper.writeFile(text); 
// forgot to fileHelper.close(); 

и вы заменяете финализац и вызвать близко() внутри, когда GC запускает файл будет закрыт. Проблемы:

  • Как уже говорилось ранее, файл должен быть закрыт как можно скорее (но не раньше;))
  • Это индетерминисти- (Никакое тело не знает, когда GC начнет)
  • Это должно быть использовано только для предотвращения случая, когда вызывающий абонент забывает закрыть файл
+0

Чтобы добавить немного цветового комментария, переопределение завершенности также делает GC более дорогим (ваш объект будет проживать, по меньшей мере, через два прохода GC), а JVM не обязана называть этот метод каким-либо своевременным способом - или даже вообще. Существуют различные статьи о финализации и GC, все из которых настоятельно рекомендуют избегать переопределения этого метода. – yshavit

+0

Конечно, но это угловой корпус. Я бы не стал беспокоиться о том, что накладные расходы на GC, когда я выполняю IO - на порядок медленнее. Соблюдайте сравнение моих роликов с реактивным двигателем. –

+0

Несомненно, но я разрабатывал в случае, когда ОП рассматривал использование метода в классах, отличных от IO. Понятно, что я упомянул об этом, пока мы по этому поводу. – yshavit

0

Переопределение finalize() не является хорошей практикой. Я бы сделал это в коде.

1

Использование финализаторов - плохая идея, практически во всех обстоятельствах. Спецификации Java утверждают, что нет гарантии, что финализаторы будут запущены. И даже если они это сделают, вы не можете контролировать, когда это может произойти.

Использование финализаторов как первичный механизм для закрытия файлов всегда плохая идея. Зачем? Потому что, если GC не запускается в течение длительного времени, ваше приложение может закончиться файловыми дескрипторами, и попытки открытия файла начнут сбой.

Лучший способ борьбы с открытыми потоками - сохранить их в локальных переменных и параметрах и использовать try { ...} finally, чтобы убедиться, что они всегда закрыты, когда вы закончили с ними. Или в Java 7 используйте новый синтаксис «попробуйте с ресурсом».

Если вам нужно поместить поток в переменную-член, вероятно, вы должны сделать родительский класс реализовать метод close(), который закрывает потоки, и использовать try { ...} finally, чтобы убедиться, что экземпляры родительского класса закрыты.


Следует также отметить, что с помощью финализатора мало смысла закрывать «потерянные» потоки. Для классов потока, использующих внешние ресурсы, которые нужны , у них уже есть финализаторы.

1

Метод finalize() будет вызван только тогда, когда сборщик мусора Java собирается вернуть объект. Плохая практика заключается в том, чтобы выпустить дескриптор файла в методе finalize.

Это может привести к появлению java.io.IOException: слишком много открытых файлов, поскольку вы не можете гарантировать, когда будет запущен сборщик мусора.

Лучшим вариантом было бы закрыть объект чтения/записи файла в блоке finally. Как это гарантировано.

finally { 
    // Always close input and output streams. Doing this closes 
    // the channels associated with them as well. 
    try { 
    if (fin != null) 
     fin.close(); 
    if (fout != null) 
     fout.close(); 
    } catch (IOException e) { 
    }} 

fin и fout - объекты FileInputStream и FileOutputStream.