Следующее решение корректно выдает исключение, если закрытие завершается неудачей, не скрывая возможного исключения до закрытия.
try {
InputStream in = new FileInputStream(file);
try {
// work
in.close();
} finally {
Closeables.closeQuietly(in);
}
} catch(IOException exc) {
// kernel panic
}
Это работает, потому что вызов закрывается второй раз has no effect.
Это зависит от guava Closeables, но, если это необходимо, можно написать собственный метод closeQuietly, как показано на рисунке squiddle (см. Также serg10).
Сообщение об ошибке закрытия в общем случае важно, так как close может записать некоторые конечные байты в поток, например. из-за буферизации. Следовательно, ваш пользователь хочет знать, если это не удалось, или вы, вероятно, хотите как-то действовать. Конечно, это может быть неверно в конкретном случае FileInputStream, я не знаю (но по уже упомянутым причинам я думаю, что лучше сообщить о закрытой ошибке, если это произойдет в любом случае).
Приведенный выше код немного сложно понять из-за структуры встроенных блоков try. Он может считаться более ясным с помощью двух методов, который генерирует исключение IOException и тот, который его ловит. По крайней мере, это то, что я бы выбрал.
private void work() throws IOException {
InputStream in = new FileInputStream(file);
try {
// work
in.close();
} finally {
Closeables.closeQuietly(in);
}
}
public void workAndDealWithException() {
try {
work();
} catch(IOException exc) {
// kernel panic
}
}
на основе http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html (на который ссылается Макдауэлл).
`fis` не может быть пустым в том месте, где вы его тестируете. Он может быть пустым в отсутствующем блоке `finally`, где вы должны его тестировать и закрывать. Но вопрос устарел после введения синтаксиса «try-with-resources». – EJP 2015-04-28 01:14:58
Я изменил код соответственно, чтобы люди не вводили в заблуждение. – 2015-04-28 14:23:57