Является ли Java EOFException исключительным? - PullRequest
5 голосов
/ 27 июля 2010

Кажется грязным использовать исключение, чтобы указать, что конец файла достигнут. У каждого файла, который мы читаем, есть конец, поэтому он не кажется исключительным или неожиданным. Кроме того, мне не нравится использовать исключение для неисключительного потока моей программы.

Я говорю об использовании java.io.EOFException для сигнализации об окончании потока ввода данных:

Представьте себе файл, состоящий из следующих сообщений ...

----------------- ------------------
- 2-byte LENGTH - - N-byte PAYLOAD - , where N = LENGTH;
----------------- ------------------

... и чтение этого файла с помощью DataInputStream:

DataInputStream in = new DataInputStream(...);

...

try {
    while (true) {
        short length = in.readShort();
        byte[] b = new byte[length];
        in.readFully(b);
    }
} catch (EOFException e) { }

...

В этом примере EOFException вызывается вызовом in.readShort(). Должен ли я вычислить количество байтов в файле и прочитать именно это количество байтов (определяемое total -= length, стремящимся к нулю) и выйти из цикла while без исключения? Я как бы ищу лучшую практику.

Должен ли я сделать что-то подобное?

long total = file.length();
while (total > 0) {
    short length = in.readShort();
    total -= length;
    byte[] b = new byte[length];
    in.readFully(b);
}

Спецификация API указывает, что EOFException указывает на то, что конец файла или конец потока достигнут неожиданно во время ввода. Но он также используется потоками ввода данных для оповещения об окончании потока.

Что мне делать, когда ожидается освобождение?

Ответы [ 3 ]

2 голосов
/ 27 июля 2010

Обратитесь к спецификации API для метода DataInput.readFully:

 This method blocks until one of the following conditions occurs:

    * b.length bytes of input data are available, in which case a normal return is made.
    * End of file is detected, in which case an EOFException is thrown.
    * An I/O error occurs, in which case an IOException other than EOFException is thrown.

Таким образом, идея заключается в том, что он либо будет читать байты данных длиной b.length, либо вы получитеошибка, если он не может этого сделать, либо из-за ошибки ввода-вывода, либо до достижения конца файла до того, как будут считаны байты b.length.

Таким образом, вы должны знать, сколько байтов вы хотите прочитать дозвонит DataInput.readFully.Если вы идете за конец файла, это считается ненормальным поведением и, следовательно, является причиной, по которой вы получаете исключение.

1 голос
/ 25 марта 2016

Вы намекаете на общеизвестный совет, что исключения должны использоваться только для сигнализации об исключительных событиях. Проблема с этим советом состоит в том, что он заменяет одну неопределенность («когда генерировать исключение») другой («что является исключительным»).

Другой и лучший ответ заключается в том, что вы должны выбросить исключение в том и только в том случае, если альтернативой будет невозможность установить условие публикации или сохранить инвариант.

Условием публикации операции чтения во входном потоке является то, что значение было успешно прочитано. Ясно, что никакое значение не может быть прочитано, если мы находимся в EOF. Таким образом, должно быть выброшено исключение некоторого типа. Вызывающий код захочет остановить чтение, поэтому это должен быть особый тип исключения (не общее IOException). Следовательно, необходимо специальное исключение EOFException.

Альтернатива заключается в том, что операции чтения не имеют успешного чтения в качестве условий публикации. Это то, что делают API C (POSIX). По сути, каждая операция чтения - это попытка чтения. Затем код читателя должен проверить код состояния, чтобы увидеть, была ли попытка чтения действительно успешной. Этот стиль кода сложен для понимания, многословен и подвержен ошибкам. одна из причин использования исключений, а не кодов состояния, состоит в том, чтобы избежать этих трудностей.

0 голосов
/ 27 июля 2010

Как следует из названия, readFully используется, когда вы ожидаете полностью прочитать несколько байтов известной длины.Если EOF достигнут раньше, это неожиданно, и тогда концептуально правильно бросить исключение.Если вам нужна семантика read, используйте метод read .

...