Java: IOException при записи в ByteArrayOutputStream?
Поскольку ByteArrayOutputStream
просто пишет в память, IOException
никогда не должно происходить. Однако из-за контракта OutputStream
интерфейс, все потоковые операции определяют IOException
в их throws
пункт.
Как правильно "справиться" с этим никогда не встречающимся IOException
? Просто заверните операции в пустую try-catch
блок?
Или есть реальные ситуации, когда ByteArrayOutputStream
может скинуть исключение?
РЕДАКТИРОВАТЬ
Как указывает Джон, ByteArrayOutputStream
не объявляет throws
пункт о write
методы, которые он определяет - однако, он наследует write(byte[])
от OutputStream
и тот бросает IOEXception
(довольно странно, что BAOS
не будет переопределять этот метод, поскольку он может заменить версию суперкласса - которая записывает один байт за раз - гораздо более эффективной arraycopy
вызов)
6 ответов
Что ж, ByteArrayOutputStream
не объявляет, что какой-либо из его методов бросает IOException
Кроме writeTo
а также close
, (Я не знаю почему close
до сих пор заявляет об этом, если честно.)
Если у вас есть ссылка типа OutputStream
хотя, конечно, вы все равно увидите декларации бросков.
Я бы не использовал пустой блок catch - я бы выбрасывал что-то вроде IllegalStateException
или аналогичное непроверенное исключение: это означает, что вы находитесь в ситуации, которую вы действительно не ожидаете, и что-то пошло не так.
Начиная с Java 11, существует также новый метод ByteArrayOutputStream.writeBytes(byte[])
который не бросает IOException
также:
/**
* Writes the complete contents of the specified byte array
* to this {@code ByteArrayOutputStream}.
*
* ...
*
* @since 11
*/
public void writeBytes(byte b[]) {
write(b, 0, b.length);
}
Вы можете использовать этот метод, если вы не хотите обрабатывать IOException
который никогда не брошен.
Я только что заметил, что ByteArrayOutputStream.write на самом деле не объявляет IOException - но Eclipse жалуется на необработанное исключение всякий раз, когда я его использую... странно.
Это легко объяснить. Вы, вероятно, сделали что-то вроде этого:
OutputStream os = new ByteArrayOutputStream();
...
os.write();
"Проблема" в том, что вы вызываете метод как OutputStream.write()
а не как ByteArrayOutputStream.write()
, Итак, компилятор говорит:
"Ах...
write()
наOutputStream
может броситьIOException
так что ты должен разобраться с этим."
Это не может сказать:
"Этот конкретный
OutputStream
действительноByteArrayOutputStream
... так что мы тебя отпустим."
потому что JLS не позволяет этого.
Это один из тех крайних случаев, когда следование "наилучшей практике" путем кодирования интерфейса, а не класса реализации возвращается к вам.
Итак...
- это нежный, не полный укус.
OutputStream
реализован как класс Java, а не как интерфейс Java, но это не относится к делу.- большинство компиляторов на самом деле не поддерживают с вами разговоров во время компиляции вашего кода:-)
Типичным клише является throw new RuntimeException(theIOException)
в блоке улова. Если случится невозможное, вы хотя бы узнаете об этом.
Цепочка исключений - лучшая практика в этой ситуации. т.е. бросить RuntimeException.
С 2002 года существует билет для улучшения этой проблемы. Причина, по которой это не устраняется, заключается в том, что это повлияет на совместимость с предыдущими версиями Java.
Здесь следуют 2 обходных пути, которые я бы рассмотрел.
Обходной путь 1
write(byte[], int, int)
Метод не генерирует проверенные исключения. Это немного более подробно, чтобы указать 2 дополнительных параметра. Но все-таки занимаемая площадь меньше без пробного улова.
baos.write(array, 0, array.length);
Обходной путь 2
Другое возможное решение, это написать свой собственный ByteUtil
класс, который ловит исключение внутри.
public final class ByteUtil
{
public static void write(ByteArrayOutputStream baos, byte[] bytes)
{
try
{
baos.write(bytes);
}
catch (IOException e)
{
// impossible
}
}
}
// usage
ByteUtil.write(baos, bytes);