Варианты шаблона закрытия потока в Java
Я часто вижу следующий шаблон как в документации Java, так и в коде других людей при работе с потоками:
FileInputStream fis = null;
try {
fis = new FileInputStream("some.file");
// do something useful with fis
} finally {
if (fis != null) {
fis.close();
}
}
Однако я лично предпочитаю другую модель:
FileInputStream fis = new FileInputStream("some.file");
try {
// do something useful with fis
} finally {
fis.close();
}
Мне нравится краткость последнего, и я думаю, что это правильно. Но прав ли я относительно правильности? Есть ли объективная причина предпочитать одно другому?
Обновить
Даже если я напишу примеры в значительной степени, как я бы написал такой код в реальной жизни, мой шаблон будет еще более кратким. Сравните подход документации:
public Object processFile(String fn) throws MyException {
FileInputStream fis = null;
try {
fis = new FileInputStream(fn);
return new Object(); // somehow derived from fis
} catch (FileNotFoundException e) {
throw new MySubExceptionForNotFound(e);
} catch (IOException e) {
throw new MySubExceptionForIoError(e);
} finally {
if (fis != null) {
IOUtils.closeQuietly(fis);
}
}
}
с моим подходом:
public Object processFile(String fn) throws MyException {
try {
FileInputStream fis = new FileInputStream(fn);
try {
return new Object(); // somehow derived from fis
} finally {
IOUtils.closeQuietly(fis);
}
} catch (FileNotFoundException e) {
throw new MySubExceptionForNotFound(e);
} catch (IOException e) {
throw new MySubExceptionForIoError(e);
}
}
Мой на одну строчку короче!:D
Интересно, что мой код не изменится, если вы решите использовать fis.close()
вместо IOUtils.closeQuietly()
пока "официальный" код вырастет еще на 4 строки.
3 ответа
Используйте try-with-resources:
try (FileInputStream fis = new FileInputStream("some.file")) {
// some code here
}
Чтобы ответить на вопрос, почему рекомендуемый шаблон такой, какой он есть, рассмотрим тот факт, что new FileInputStream(String)
выдает проверенное исключение, которое вы, вероятно, должны поймать;
FileInputStream fis = null;
try {
fis = new FileInputStream("somefile.txt");
} catch (FileNotFoundException e) {
return false;
} finally {
if (fis != null) {
fis.close();
}
}
позволяет обрабатывать его в том же блоке try / catch, что и другие исключения, связанные с файлами. Это имеет краткость и уменьшает вложенные преимущества по сравнению со следующими:
try {
FileInputStream fis = new FileInputStream("some.file");
try {
// do something useful with fis
} finally {
fis.close();
}
} catch (FileNotFoundException e) {
return false;
}
И если вы не перехватываете исключение и просто позволяете ему распространяться, тогда ваше предложение будет чище - однако, учитывая интенсивное использование проверенных исключений в библиотеках ввода-вывода (в том числе из конструкторов классов), перехват и обработка исключения достаточно распространены, и Я думаю, что имеет смысл иметь только один шаблон для учебных целей вместо того, чтобы показывать кому-то немного другой шаблон каждый раз.
Второй пример не компилируется, если вы не выбросите исключение из метода, потому что FileNotFoundException
это проверенное исключение.
Compile.java:5: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
FileInputStream fis = new FileInputStream("some.file");
Первый пример также не компилируется, потому что вам не хватает соответствующего catch
блок. Вот пример компиляции.
import java.io.*;
public class Compile {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("some.file");
// do something useful with fis
if (fis != null) {
fis.close();
}
}
catch (FileNotFoundException fnf) {
}
catch (IOException ioe) {
}
finally {
}
}
}
Второй пример, который вы опубликовали, не будет пытаться / поймать возможные ошибки, которые ... = new FileInputStream("...");
вернется, если не удастся загрузить файл. В первом примере вы автоматически обнаруживаете ошибки, которые FileInputStream
дает.
Я лично пошел бы с первым, чтобы иметь лучшую обработку ошибок.