是否有可能找出可能抛出的所有可能的异常,这些异常不一定由方法的签名列出。
有2个案例
1)不必声明的运行时异常(显然有些是显而易见的,例如空指针,但是还有其他我想要捕获的运行时异常,这可能是由于数据不好,而在开发我不知道是不好的数据。)
2)异常是签名中列出的异常的子类。
动机示例
想象一下我在HttpURLConnection对象上调用getInputStream(),它会抛出java.io.Exception,但实际上,它会抛出其他异常,这些异常是java.io.Exception(ala java.io.FileNotFoundException)的子句,我是我想以一种独特的方式处理(即不想将所有java.io.Exceptions混为一谈)。
所以虽然我可以通过捕获java.io.Exception并打印出实际的异常,然后修改代码来处理这种情况来实践,但是想知道是否有更好的方法:)
感谢
编辑:我认为人们错过了我的第二个问题。抛出与方法签名完全一致的已检查异常的方法,但由于方法的签名只具有某种基类,因此未在其中列出。
答案 0 :(得分:2)
是否有可能找出所有可能的例外情况 投掷不一定按方法的签名列出。
简单回答:不是真的。
我的回答很大程度上基于this document,因此我建议您阅读本文档,以了解为什么Java设计人员无需处理所有可能的异常。将unchecked exception
作为文档的原因在于:
运行时异常代表的问题是 编程问题的结果,以及API客户端代码 不能合理地期望从他们那里恢复或处理他们 以任何方式。这些问题包括算术异常,例如 除以零;指针异常,例如尝试访问 通过null引用对象;和索引例外,例如 试图通过索引访问数组元素 大或小。
运行时异常可以发生在程序的任何地方,也可以是典型的 一个他们可以很多。必须添加运行时异常 每个方法声明都会降低程序的清晰度。就这样 编译器不要求您捕获或指定运行时异常 (虽然你可以)。
所以,在我看来,寻找所有可能的例外并不是一个好主意。例如,OutOfMemoryError
没有意义。事实上,捕获这样的例外也被认为是一种不好的做法。
答案 1 :(得分:2)
没有。您原则上不能事先知道CLASSPATH在运行时会出现什么异常类,一开始,也不能提前知道实现您正在查看的接口的可能类集,或者扩展您正在查看并重写该方法的类,除非该类或方法是最终的。您自己的示例就是一个很好的例子:您正在查看HttpURLConnection
,但它是一个抽象类,并且在运行时出现的实际实现类可能因您的配置而异:HTTP URLStreamHandler
使用的类可以重新定义,以便使用返回HttpURLConnection
的不同实现的类。
答案 2 :(得分:1)
这是一个棘手的问题。
有一个相对简单的“非解决方案”。静态分析器应该能够枚举应用程序类库中可用的所有未经检查的异常;以及任何已检查异常的所有子类。当然,这会产生很多误报;即方法签名允许的异常,但不可能在调用中抛出。
要找出可能真正抛出的异常,您需要使用某种字节码或源代码操作框架来分析代码。应该可以确定在给定方法调用中可能使用的Java方法的闭包中提到的类的异常类的集合。但是Java代码中没有提到一些例外。这包括JVM本身抛出的运行时异常和错误,以及本机代码库可能抛出的其他异常和错误。并且有可能在运行时注入异常抛出代码;例如使用动态代理。最后,您遇到的问题是,某些异常只会在特定应用程序中被证明是不可能的情况下抛出。
因此,虽然我可以通过捕获java.io.Exception并打印出实际的异常,然后修改代码来处理这种情况来实践,但是想知道是否有更好的方法。
是的。一个更好的方法是读取javadoc,使用常识来确定可能的异常,如果您有疑问,请阅读源代码。
另一点是,您通常不需要知道所有可能的例外情况,以便有效地处理它们。
最后,由于抛出的实际异常可能因JVM而异(这些是实现细节!),因此在代码中假设可能会抛出哪些异常是一个坏主意。
答案 3 :(得分:0)
在字节码级别,已检查的异常不存在,因此,如果您正在调用字节码方法,则无论方法签名如何,都可以抛出任何内容。这也意味着您可以使用反射或自定义类加载器从纯Java中执行相同操作。
您还可以使用Thread.stop