Стиль 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 давно.