10

今天我正在使用 Java 类StringReader,我发现它在read方法上抛出 IOException 非常烦人。我知道它扩展Reader了方法read抛出 IOException 的类,但我认为 StringReader 不需要它。此类不使用任何可能导致错误的外部资源。

经过短暂的调查后,我发现如果此类读取的字符串为 null 则StringReader#read抛出IOException,但事实上这不会发生,因为如果我们尝试将 null 传递给StringReader构造函数,它会抛出 NPE。

你怎么看,总是抛出与超类相同的异常是一种好习惯吗?


编辑:正如 U Mad Reader 所指出的,它是一个类而不是接口。

4

3 回答 3

7

如果您的实现确保它永远不会发生,我认为抛出与超类或接口定义相同的异常不是一个好习惯。我总是将签名减少到所需的最低限度。

所有可以想象的IOException实现都需要它,包括文件源、流和套接字等。如果没有,这样的实现就不能将它们的错误作为检查异常通知。但是,如果一个实现不需要抛出一个检查异常(这对于调用代码来说通常很烦人),将它从实现类中删除并没有什么害处,但会减轻一些负担。

更新:

我找到了方法 read()必须抛出IOException: 的原因,因为为 close() 方法定义的合同。来自 JavaDoc:

关闭流并释放与其关联的任何系统资源。关闭流后,进一步的 read()、ready()、mark() 或 reset() 调用将引发 IOException。关闭以前关闭的流没有效果。

于 2014-04-17T07:36:56.950 回答
5

请看一下StringReader#read()

查看StringReader#read()方法的源代码。它调用ensureOpen()实​​际抛出的方法,IOException因为ensureOpen()检查以确保流尚未关闭。

如果阅读器关闭然后read()再次调用之后会发生什么?

直接来自以上链接的源代码(查看评论):

/**
 * Reads a single character.
 *
 * @return     The character read, or -1 if the end of the stream has been
 *             reached
 *
 * @exception  IOException  If an I/O error occurs
 */
public int read() throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (next >= length)
            return -1;
        return str.charAt(next++);
    }
}

/** Check to make sure that the stream has not been closed */
private void ensureOpen() throws IOException {
    if (str == null)
        throw new IOException("Stream closed");
}

/**
 * Closes the stream and releases any system resources associated with
 * it. Once the stream has been closed, further read(),
 * ready(), mark(), or reset() invocations will throw an IOException.
 * Closing a previously closed stream has no effect.
 */
public void close() {
    str = null;
}
于 2014-04-17T07:40:50.327 回答
1

当您在类中实现接口方法时,不需要提供相同的异常参数。当您覆盖超类的方法声明时,同样的情况也适用。

public class MyReader implements Readable {

    @Override
    public int read(CharBuffer cb)  {
        return 0;
    }

}

但是你没有以正确的方式使用界面。如果您对接口进行编码,则不会从中受益。

Readable readable = new MyReader();

        try {
            readable.read(null);
        } catch (IOException e) {
            e.printStackTrace();
        }

即使在MyReader不暴露的情况下,IOException您仍然必须使用 try 块。因此,如果您不抛出您实现的方法的异常,可能会指出您在该方法的实现中遗漏了一些东西。所以恕我直言,这样做不是一个好习惯。

StringBuilderthrows的原因IOException不是它实现了接口Readable。原因是验证方法中的输入,当输入为空时ensureOpen()抛出一个。然后在调用IOException方法或将 null 传递给构造函数时,输入可以为 null 。close()由于方法 close 是抽象的,它必须在子类中产生一些影响。预期的是,在您调用 close 后,您将无法再从中读取,您将获得 IOException。

这是考虑到所有潜在用例的完美、干净和可靠的实现。

于 2014-04-17T08:01:04.570 回答