为什么 ByteArrayOutputStream.close() 会抛出 IOException?

5
为什么ByteArrayOutputStreamclose声明中带有throws IOException
首先,实际上它不会抛出任何异常,因为它的方法体是空的。其次,根据文档描述,它也不应该抛出任何异常,因为“关闭ByteArrayOutputStream没有任何效果”。
这难道不是一个小错误吗?
是的,我知道它的超类OutputStream实现了Closable接口,而后者的close方法允许抛出IOException。但是,没人禁止在ByteArrayOutputStream中覆盖它,并定义一个不带异常声明的close方法。(即使在Java的一些过时版本中禁止用一个抛出更多异常的方法去覆盖另一个抛出较少异常的方法,但改变ByteArrayOutputStreamclose定义现在不会导致不兼容的变化。)

2
如果更改了定义,则捕获IOException的现有代码将出现编译错误“无法访问IOException的catch块。此异常从try语句体中永远不会抛出”。 - user4910279
@saka1029:我认为,你走在了正确的道路上。 - Holger
@saka1029,你是对的(我以为它会引起警告,而不是错误)。 - Sasha
1个回答

4
除了疏忽之外,最合理的解释是兼容性。早在Java 1.1时期,ByteArrayOutputStream 没有重写 close(),因此它从OutputStream继承了该方法,后者声明了IOException。那时可能是一个疏忽。也许开发人员认为这是不必要的,因为没有人会在ByteArrayOutputStream上调用close()。但文档中缺乏关于调用close()是否不必要的明确说明。
自Java 1.2(也称为Java 2)以来,ByteArrayOutputStream确实覆盖了close()。但是,删除throws子句会导致在try块中未抛出异常的情况下,在调用ByteArrayOutputStream上的close()并捕获已检查的IOException的代码中产生编译时错误。由于这不影响二进制兼容性,因此可能看起来很奇怪,考虑到自那时以来对源代码进行了更大的影响的变化。

但是,这个决定是在很久以前做出的。而且也不清楚为什么添加了这个覆盖,因为继承的空操作已经足够了,覆盖也没有改变签名,也没有在该版本中包含有用的文档改进,即没有关于close()不必要的澄清。最合理的解释是它是带着删除throws子句的意图添加的,但后来发现不兼容性是某些现有代码的问题。

最终,删除它并不是真正重要的。如果您的编译时类型是 ByteArrayOutputStream,则知道您不需要调用 close()。在所有其他情况下,即如果编译时类型是更一般的 OutputStream,则必须 close() 并处理声明的 IOException...

我明白,删除它并不是非常重要。 - Sasha
实际上,答案的主要部分是由@saka1029介绍的:我不知道删除throws子句确实会引入不兼容性。我认为这个事实(删除throws子句可能会引入源不兼容性;“Unreachable catch block for…”是一个错误,而不是一个警告)本身就是一个错误。 - Sasha
@saka1029的话是一条注释(而不是答案),所以我不能接受它(尽管它出现得最早且简洁,但我非常想这样做)。 - Sasha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接