使用异常表示已到达文件末尾似乎很脏。我们阅读的每个文件都有一个结尾,所以它似乎并不特殊或意外。此外,我不喜欢对我的程序的非异常流程使用异常。
我说的是使用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) { }
...
在此示例中,调用in.readShort()
会引发EOFException。我应该计算出文件中的字节数,并准确读取该字节数(由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表示文件的结尾或流的结尾意外。但是它也被数据输入流用来表示流的结束。
预计例外时我该怎么办?
答案 0 :(得分:2)
有关DataInput.readFully
方法的信息,请参阅API specification:
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个字节的数据,要么因为I / O错误或者在b.length个字节之前达到文件结尾而得到错误。请阅读。
因此,在调用DataInput.readFully
之前,您需要知道要读取的字节数。如果你超过了文件的末尾,那就被认为是异常行为,因此,这就是你获得异常的原因。
答案 1 :(得分:1)
您提到了通常给出的建议,即异常应仅用于发出异常事件的信号。这个建议的问题在于它取代了一个不确定性("何时抛出异常')与另一个("什么是例外")。
另一个更好的答案是,当且仅当替代方案未能建立后置条件或维持不变量时,您应该抛出异常。
对输入流的读取操作的后置条件是已成功读取值。显然,如果我们在EOF,就无法读取任何价值。因此必须抛出某种类型的异常。调用代码希望暂停读取,因此它必须是一种独特的异常类型(不是一般的IOException)。因此,特定的EOFException是必要的。
另一种方法是读取操作没有成功读取作为后置条件。这就是C(POSIX)API的功能。实际上,每次读取操作实际上都是一种尝试读取操作。然后,读者代码需要检查状态代码以查看读取的尝试是否实际成功。这种代码风格难以理解,冗长且容易出错。使用例外而不是状态代码的动机之一就是避免这些困难。
答案 2 :(得分:0)
顾名思义,当您希望完全读取已知长度的一些字节时,会使用readFully
。如果之前达到EOF,那是意料之外的,那么从概念上讲它是正确的抛出异常。如果您需要read
语义,请使用read方法。