Java: IOException при записи в ByteArrayOutputStream?

Поскольку ByteArrayOutputStream просто пишет в память, IOException никогда не должно происходить. Однако из-за контракта OutputStream интерфейс, все потоковые операции определяют IOException в их throws пункт.

Как правильно "справиться" с этим никогда не встречающимся IOException? Просто заверните операции в пустую try-catch блок?

Или есть реальные ситуации, когда ByteArrayOutputStream может скинуть исключение?

(См. Также: Как я могу обработать исключение IOException, которое, как я знаю, никогда не может быть сгенерировано безопасным и читаемым способом?)

РЕДАКТИРОВАТЬ

Как указывает Джон, 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);
Другие вопросы по тегам