Если вы пытаетесь отследить и сообщить обо всех исключениях в источнике, лучшим решением будет следующее:
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(shapes);
oos.flush();
} catch (FileNotFoundException ex) {
// complain to user
} catch (IOException ex) {
// notify user
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException ex) {
// ignore ... any significant errors should already have been
// reported via an IOException from the final flush.
}
}
}
Примечания:
- Стандартные потоки-обертки Java, читатели и писатели распространяют
close
и flush
на свои обернутые потоки и т. Д. Так что вам нужно только закрыть или очистить самую внешнюю обертку.
- Цель явной очистки в конце блока try состоит в том, чтобы (реальный) обработчик для
IOException
мог видеть любые ошибки записи 1 .
- Когда вы выполняете закрытие или сброс потока выходного потока, существует вероятность «один раз в синей луне», что будет сгенерировано исключение из-за ошибок диска или переполнения файловой системы. Вы не должны раздавить это исключение! .
Если вам часто приходится «закрывать возможно нулевой поток, игнорируя исключения IOException», то вы можете написать себе вспомогательный метод, подобный этому:
public void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ex) {
// ignore
}
}
}
тогда вы можете заменить предыдущий блок finally на:
} finally {
closeQuietly(oos);
}
(Другой ответ указывает на то, что метод closeQuietly
уже доступен в библиотеке Apache Commons ... если вы не возражаете добавить в свой проект зависимость для метода из 10 строк. UPDATE : обратите внимание, что эти методы устарели в версии 2.6 API.)
Но будьте осторожны, вы используете closeQuietly
только в тех потоках, где исключения ввода-вывода на самом деле не имеют значения.
1 - в использовании try-with-resources нет необходимости.
По вопросу flush()
против close()
, о котором спрашивают люди:
- Стандартные «фильтрующие» и «буферизованные» выходные потоки и средства записи имеют контракт API, который гласит, что
close()
вызывает сброс всех буферизованных выходных данных. Вы должны обнаружить, что все другие (стандартные) выходные классы, которые выполняют буферизацию вывода, будут вести себя одинаково. Таким образом, для стандартного класса избыточно вызывать flush()
непосредственно перед close()
.
- Для пользовательских и сторонних классов вам нужно исследовать (например, прочитать javadoc, посмотреть код), но любой метод
close()
, который не сбрасывает буферизованные данные, вероятно, сломан .
Наконец, существует проблема того, что на самом деле делает flush()
. Вот что говорит Javadoc (для OutputStream
...)
Если предполагаемым местом назначения этого потока является абстракция, предоставляемая базовой операционной системой, например файлом, то очистка потока гарантирует только то, что байты, ранее записанные в поток, передаются в операционную систему для записи; это не гарантирует, что они действительно записаны на физическое устройство, такое как дисковод.
Так что ... если вы надеетесь / представляете, что вызов flush()
гарантирует, что ваши данные сохранятся, вы ошибаетесь! (Если вам нужно поступить подобным образом, посмотрите на FileChannel.force
метод ...)
С другой стороны, если вы можете использовать Java 7 или более позднюю версию, «новая» попытка с ресурсами, как описано в ответе @Mike Clark, является лучшим решением.
Если вы не используете Java 7 или более позднюю версию для своего нового кода, вы, вероятно, находитесь в глубокой яме и копаете глубже.