Стиль Java-кода для открытого потока try/finally block
Это вопрос стиля кода. Я замечаю много примеров кода, включая некоторые примеры из Oracle, чтобы поток был закрыт следующим образом:
InputStream in = null;
try {
in = acquireStream();
...
} finally {
if (in != null) in.close();
}
Обратите внимание на инициализацию на null и проверьте значение null в блоке finally
.
Я обычно пишу код следующим образом:
InputStream in = acquireStream();
try {
...
} finally {
in.close();
}
Есть ли преимущества или недостатки любого подхода? Мне нравится мой стиль, потому что мне не нужна нулевая проверка. Также мне нравится избегать null
, когда это возможно. Но поскольку стиль Oracle настолько распространен в онлайн-примерах, мне интересно, есть ли у моей скрытая ошибка.
Я задаю один и тот же вопрос для InputStream
, OutputStream
, java.sql.Connection
, java.sql.PreparedStatement
и т.д. Я, как правило, приобрел ресурс вне блока try
, а затем закрою его в finally
без нулевого проверить. Есть ли что-то, что я упускаю, кроме стилистических различий?
Спасибо.
Ответы
Ответ 1
Так как Java 7 существует гораздо лучший способ записать блок try-finally в отношении ресурсов Closeable
.
Теперь вы можете создавать свои ресурсы в скобках после ключевого слова try
, например:
try (init resources) {
...
}
И после завершения кода кода они будут закрыты автоматически. Нет необходимости закрывать потоки в блоке finally
.
Пример:
try (
ZipFile zf = new ZipFile(zipFileName);
BufferedWriter writer = Files.newBufferedWriter(outputFilePath, charset);
) {
// Enumerate each entry
for (Enumeration entries = zf.entries(); entries.hasMoreElements();) {
// Get the entry name and write it to the output file
String newLine = System.getProperty("line.separator");
String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
}
И после того, как цикл for
будет завершен, ресурсы будут закрыты!
Ответ 2
Ответ: нет, нет скрытой ошибки, когда вы делаете это по-своему. Это чисто стиль.
Я обычно никогда не пытаюсь поймать блок finally, только попытаюсь поймать блоки и попробовать наконец блокировать.
Они, как правило, выглядят так:
try {
InputStream in = acquireStream();
try {
...
} finally {
in.close();
}
} catch (IOException e) {
... handle exception
}
Нет причин помещать getStream() в блок finally try. Если in никогда не привязано к действительному потоку, вы никогда не сможете его закрыть. Явная нулевая проверка совершенно не нужна. Кроме того, редко вы хотите обрабатывать исключение в close() иначе, чем исключение в основном блоке обработки.
Ответ 3
Обычно у вас есть try
, catch
, finally
. В этом случае выгодно использовать стандартный метод SUN, потому что вы можете зафиксировать любые ошибки, которые произошли в acquireStream()
внутри try
, catch
.
Ответ 4
Я бы использовал
InputStream in = null;
try {
in = acquireStream();
...
} finally {
if (in != null) in.close();
}
if aquireStream()
вызывает любое исключенное исключение, и я планирую обработать его.
Иначе я буду использовать этот
InputStream in = acquireStream();
try {
...
} finally {
in.close();
}
на NPE:
Я бы предпочел позволить NPE распространяться и не обрабатывать какое-либо исключение во время выполнения.
Ответ 5
Я думаю, что безопаснее приобретать поток в блоке try.
Есть еще один вариант для закрытия - вместо проверки на null вы можете сделать следующее:
finally {
IOUtils.closeQuietly(in);
}
Это требует от Apache Commons-IO этого, но он сделает нулевую проверку для вас. Это также приятный способ стилистически сделать это.
Ответ 6
Если ваш метод полученияStream() возвратил null, вы получите NPE, когда попытаетесь закрыть свой поток в блоке finally, и он будет неактивен.
Ответ 7
Я пользуюсь первым. Некоторые операторы ввода-вывода требуют, чтобы они находились внутри try/catch для
некоторые условия. Кроме того, операции могут всегда возвращать нуль неожиданно,
даже если это не в руководстве.
Ответ 8
Я обычно делаю это:
InputStream in = null;
try {
in = acquire();
...
} finally {
if( in != null ) try {
in.close();
} catch( IOException ioe ) {
// ignore exception while closing
}
}
При закрытии ресурса может быть выбрано исключение, и в этом случае вам понадобится дополнительный try/catch, но в большинстве случаев для меня это игнорировать (я все-таки закрываю), но это единственное место, где я использую if без брекетов.
Я видел это из Huckster code давно.