3

是否有可能找出方法签名不一定列出的所有可能引发的异常。

有2个案例

1) 不必声明的运行时异常(显然有些是显而易见的,例如空指针,但我想捕获其他运行时异常,这可能是由于数据不正确,而在开发过程中我不这样做'不知道是坏数据呢)。

2) 作为签名中所列异常的子类的异常。

一个动机的例子

想象一下,我在 HttpURLConnection 对象上调用 getInputStream(),它会抛出 java.io.Exception,但实际上,它会抛出其他异常,这些异常是 java.io.Exception (ala java.io.FileNotFoundException) 的子类,这是我想要的以独特的方式处理(即不想将所有 java.io.Exceptions 混为一谈)。

因此,虽然我可以通过捕获 java.io.Exception 并打印出实际异常来在实践中学习,然后修改代码来处理这种情况,但我想知道是否有更好的方法 :)

谢谢

编辑:我认为人们错过了我的第二个问题。抛出与方法签名完全一致的检查异常的方法,但由于该方法的签名仅具有某种基类,因此未在其中列出。

4

4 回答 4

2

是否有可能找出方法签名不一定列出的所有可能引发的异常。

简单的回答:不是。

我的回答很大程度上基于此文档,因此我建议您阅读此文档以了解为什么 Java 设计人员没有让您必须处理所有可能的异常。unchecked exception正如文件所言,背后的原因是:

运行时异常表示由编程问题引起的问题,因此,不能合理地期望 API 客户端代码从它们中恢复或以任何方式处理它们。此类问题包括算术异常,例如除以零;指针异常,例如试图通过空引用访问对象;和索引异常,例如尝试通过太大或太小的索引访问数组元素。

运行时异常可以在程序中的任何地方发生,并且在一个典型的程序中它们可能非常多。必须在每个方法声明中添加运行时异常会降低程序的清晰度。因此,编译器不需要您捕获或指定运行时异常(尽管您可以)。

因此,在我看来,寻找所有可能的异常并不是一个好主意。例如,它没有意义OutOfMemoryError。事实上,捕获这样的异常也被认为是一种不好的做法。

于 2012-08-12T03:32:17.227 回答
2

不。原则上,您无法提前知道运行时 CLASSPATH 上将出现哪些异常类,首先,您也无法提前知道实现您正在查看的接口的可能的类集,或者扩展您正在查看的类并覆盖该方法,除非该类或方法是最终的。您自己的示例就是一个完美的例子:您正在查看HttpURLConnection,但它是一个抽象类,运行时出现的实际实现类可能会因您的配置而异:URLStreamHandler可以重新定义使用的 HTTP 类以便使用一个返回不同的实现HttpURLConnection

于 2012-08-12T04:14:47.680 回答
1

这是一个棘手的问题。

有一个比较简单的“无解”。静态分析器应该能够枚举应用程序类库中可用的所有未经检查的异常;以及任何已检查异常的所有子类。当然,这会产生很多误报;即方法签名允许但不可能在调用中抛出的异常。

要找出真正可能引发的异常,您需要使用某种字节码或源代码操作框架来分析代码。应该可以确定在给定方法调用中可能使用的 Java 方法的闭包中提到的类的异常类集。但是,Java 代码中没有提到一些例外情况。这包括 JVM 本身抛出的运行时异常和错误,以及本机代码库可能抛出的其他异常。并且有可能在运行时注入异常抛出代码;例如使用动态代理。最后,您遇到的问题是,某些异常只会在可证明不可能的情况下引发......在给定的应用程序中。


因此,虽然我可以通过捕获 java.io.Exception 并打印出实际异常,然后修改代码来处理这种情况来在实践中学习,但我想知道是否有更好的方法。

是的。更好的方法是阅读 javadoc,使用您的常识来找出可能的异常,如果您有疑问,请阅读源代码。

另一点是您通常不需要知道所有可能的异常来有效地处理它们。

最后,由于实际抛出的异常可能因一个 JVM 而异(这些是实现细节!),所以在代码中准确地假设可能抛出的异常是一个坏主意。

于 2012-08-12T03:32:41.407 回答
0

在字节码级别,不存在已检查异常,因此如果您正在调用字节码方法,则可以抛出任何东西,而不管方法签名如何。这也意味着您可以使用反射或自定义类加载器从纯 Java 中执行相同的操作。

您还可以使用强制代码抛出任何异常Thread.stop

于 2012-08-12T03:32:52.157 回答