什么时候可以捕获NullPointerException?

500*_*ong 16 java nullpointerexception

有效的java建议我们不应该catch NullPointerException.总是对的吗?

在许多捕捉的情况下NullPointerException,捕捉身体只打电话printStackTrace().

如果我不赶上NullPointerException并打电话printStackTrace(),我怎么能检查exception发生的地方?

而且如果我抓住NullPointerException并且catch身体是空的,那么我们当时无法得到任何堆栈信息,是吗?

UPDATE

我分析了google android源码AOSP4.2.2_r1.2中捕获RuntimeException的统计信息.

有249个RuntimeException捕获,以下是catch-body的统计信息.

42%: throw it again as other Exceptions (RuntimeException: 33%, others: 8%)

32%: just return null or 0/false/true or other default values

14%: just call log or printstacktrace

5%: just comment like "// Fall through.", "// ignore, not a valid type.", "// system process dead", "// do nothing"

2%: empty body

3%: display error messages or send fail codes (ex. network service discovery failed: replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); )


3%: intialize or reset related variables.
Run Code Online (Sandbox Code Playgroud)

在几乎情况下,dalvik和外部通过抛出其他异常来处理NPE.

但是框架通常通过返回null或其他值来处理.

  1. 你是否认为将其他例外投入捕获体内并不坏或处理好?

  2. 如果NPE出现在更高级别(例如应用程序)并且开发人员确认异常并不重要,因为应用程序是完全独立的,我可以接受我们的开发人员通过捕获来忽略NPE吗?

还有一件事,

我可以得出结论,谷歌android框架源代码可能会有些不稳定RuntimeException吗?

Ste*_*n C 37

有效的java建议我们不要捕获NullPointerException.总是对的吗?

几乎在所有情况下都是正确的.

NullPointerException通常是一个bug的结果; 即您的应用程序null在未预料到的情况下遇到对象引用,然后尝试使用它.在这种情况下,由于您(程序员)没有预料到null,因此几乎不可能知道尝试恢复是否安全,和/或知道可能需要什么"补救".因此,最好的办法是让NPE传播到基本级别,然后将其视为通用错误.(在"网络服务"应用程序中,可能适合返回"服务错误"响应,并尝试继续.)

另一种情况是您(程序员)预期null可能会交付.在这种情况下,最好的策略是(几乎总是)null 您尝试使用它之前明确地测试它,从而避免 NPE ......以及处理它的需要.有两个原因:

  • 异常处理通常很昂贵.实际上它可能比测试a的价格贵很多个数量级null.

  • 如果您允许预期的NPE发生然后捕获它,您也有可能捕获其他意外的 NPE ......并且错误地处理它们.


请注意,我通过说"几乎总是"来证明上述内容.从理论上讲,可能会有一个场景,其中明确的测试null会使代码混乱,以至于至少值得考虑允许NPE发生.但是,仍然存在意外的NPE的可能性......取决于代码.因此,这种方法始终是潜在的脆弱.

(FWIW - 我从来没有遇到过这个好主意的真实案例......)


在很多捕获NullPointerException的情况下,catch body只调用printStackTrace().

这可能是糟糕的代码.无所事事很少是从NPE中恢复的正确方法.

如果我没有捕获NullPointerException并调用printStackTrace(),我如何检查发生异常的位置?

您让NPE传播到基准级别.在那里你捕获并打印(或记录)所有未处理异常的堆栈跟踪,然后挽救或尝试恢复......如果这是可行的.

而且如果我捕获NullPointerException并且catch体是空的,那么我们当时无法得到任何堆栈信息,是吗?

永远不要这样做!它被称为"挤压"并且是危险的.(特别是因为,正如我上面解释的那样,NPE可能是由于你/你的代码没有预料到的.)

不,如果你这样做,你就无法获得堆栈跟踪.它消失了.


跟进

我对"避免NPEs"的一些一般策略没有太多的信任/信心1.例如这样的东西:

return (someObject != null) ? someObject.toString() : "";
Run Code Online (Sandbox Code Playgroud)

总是让我怀疑程序员没有考虑问题.为什么someObject一个人null在第一位?

NPE是由于null您没有预料到的原因造成的.因此,NPE通常是问题的症状而不是实际问题本身.在我看来,NPE是不可避免的.相反,您应该使用NPE来查找并修复意外的根本原因null.像上面那样避免NPE的代码妨碍了这个目标.

所以我更喜欢/推荐避免null意外地方价值的策略.

  • 确保每个引用字段都被初始化为非空值...除非null有意义的值.

  • 尽量避免使用null有意义的值,尤其是在有替代方法的情况下.例如,一个空字符串,一个零长度数组,一个空集合,一个表示"未定义"或其他的可分辨实例.或者,对于Java 8及更高版本,请使用Optional.

  • 不要null作为错误或特殊情况的指示返回.(抛出异常或返回一个值.)

  • 尽早检查未预料到的null值(例如null参数),并尽快抛出NPE .

  • null争论或结果合法的少数地方,请确保您的javadocs清楚明确地记录了这一点.如果没有文档,那么暗示应该null是不允许的,不会被返回.

无论您在哪里获得NPE,请确保找到并修复问题的真正来源......而不仅仅是抛出异常的特定语句.

1 - 了解标准Java API中null使用(或滥用)作为返回值的位置是有价值的.例如,Class.getResourceAsStream(...)HttpRequest.getParam(...).那些"避免NPE的建议"文件在指出这些陷阱方面非常有用.