什么时候可以捕获 NullPointerException? [英] When is it OK to catch NullPointerException?

查看:19
本文介绍了什么时候可以捕获 NullPointerException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Effective java 建议我们不要catch NullPointerException.总是对的吗?

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

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

而且如果我捕捉到 NullPointerException 并且 catch 主体是空的,我们在那个时候无法获得任何堆栈信息,可以吗?

更新

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

有 249 个 RuntimeException 捕获,以下是捕获体的统计数据.

42%:作为其他异常再次抛出(RuntimeException:33%,其他:8%)32%:只返回 null 或 0/false/true 或其他默认值14%:只需调用 log 或 printstacktrace5%:只是像//失败."、//忽略,不是有效类型."、//系统进程已死"、//什么都不做"之类的评论2%:空身体3%:显示错误信息或发送失败代码(例如网络服务发现失败:replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, NsdManager.FAILURE_INTERNAL_ERROR);)3%:初始化或重置相关变量.

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

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

  1. 你认为在 catch-body 中抛出其他 Exceptions 是不是不好或好处理?

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

还有一件事,

我可以断定google android框架源代码在RuntimeException方面可能有些不稳定吗?

解决方案

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

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

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

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

  • 异常处理通常很昂贵.实际上,它可能比测试 null 的成本高许多数量级.

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

<小时>

请注意,我通过说几乎总是"来限定上述内容.理论上可能会出现这样一种场景,其中对 null 的显式测试使您的代码混乱不堪,以至于至少值得 考虑 允许 NPE 发生.但是,仍然存在意外 NPE 的可能性......取决于代码.所以这种方法总是潜在脆弱的.

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

<小时><块引用>

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

那可能是糟糕的代码.什么都不做很少是从 NPE 中恢复的正确方法.

<块引用>

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

您让 NPE 传播到基本级别.在那里,您可以捕获并打印(或记录)所有 未处理异常的堆栈跟踪,然后退出或尝试恢复……如果可行的话.

<块引用>

而且如果我捕获 NullPointerException 并且捕获主体为空,那么我们此时无法获取任何堆栈信息,可以吗?

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

不,如果您这样做,您将无法获得堆栈跟踪.没了.

<小时>

跟进

对于避免 NPE"的一些一般策略,我不太信任/相信1.例如这样的东西:

return (someObject != null) ?someObject.toString() : "";

总是让我怀疑程序员没有考虑问题.为什么 someObject 首先是 null?

NPE 是由于在您不期望的位置存在 null 引起的.因此,NPE 通常是问题的症状,而不是实际问题本身.在我看来,NPE 不是可以避免的.相反,您应该使用 NPE 来查找和修复意外 null根本原因.像上面这样的代码可以避免 NPE 妨碍实现该目标.

所以我更喜欢/推荐在意想不到的地方避免 null 值的策略.

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

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

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

  • 尽早检查意外的null 值(例如null 参数),并尽早抛出NPE.p>

  • 在少数几个 null 参数或结果是合法的地方,请确保您的 javadoc 清楚明确地记录了这一点.如果没有文档,则暗示应该是不允许 null 并且不会返回.

无论您在何处获得 NPE,请确保您找到并修复问题的真正根源……而不仅仅是引发异常的具体语句.

1 - 了解标准 Java API 中 null 被用作(或滥用)作为返回值的地方是有价值的.例如,Class.getResourceAsStream(...)HttpRequest.getParam(...).那些避免 NPE 的建议"文档在指出这些陷阱的同时也很有用.

Effective java recommends that we shouldn't catch NullPointerException. Is it always right?

In many cases of catching NullPointerException, catch body only calls printStackTrace().

If I don't catch NullPointerException and call printStackTrace(), how I can check the place where the exception occurred?

And also if I catch NullPointerException and the catch body is empty, we cannot get any stack information at that time, can we?

UPDATE

I analyzed statistics of catching RuntimeException in google android source, AOSP4.2.2_r1.2.

There are 249 RuntimeException catchings and followings are statistics of 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.

In almost cases, dalvik and external handle NPE by throwing other Exceptions.

But frameworks usually handle by returning null or other values.

  1. Do you think that throwing other Exceptions in catch-body is not bad or good handling?

  2. If NPE occured in higher levels(ex. applications) and the developer confirms the exception is not critical because the app is fully independent, can I accept for our developer to ignore the NPE by catching?

and one more thing,

Can I conclude that google android framework source code may be some unstable in aspects of RuntimeException?

解决方案

Effective java recommend that we shouldn't catch NullPointerException. Is it always right?

In nearly all cases it is correct.

NullPointerException is usually a result of a bug; i.e. your application encountered a null object reference in a situation where it was not anticipated, and then attempted to use it. In this scenario, since you (the programmer) did not anticipate the null, it is next to impossible to know whether it is safe to attempt to recover, and / or to know what "remediation" might be required. So the best thing to do is to let the NPE propagate to the base level, and then treat it as a generic bug. (In "network service" applications, it may be appropriate to return a "service error" response, and attempt to continue.)

The other scenario is where you (the programmer) anticipate that a null might be delivered. In this case, the best strategy is (nearly always) to explicitly test for the null before you attempt to use it, thereby avoiding the NPE ... and the need to handle it. There are two reasons for this:

  • Exception handling is typically expensive. Indeed it can be many orders of magnitude more expensive than testing for a null.

  • If you allow the expected NPE to happen and then catch it, you are liable to also catch other unexpected NPEs ... and handle them incorrectly.


Note that I qualified the above by saying "nearly always". It is theoretically possible to have a scenario where explicit tests for null clutter up your code so much that it is at least worth considering allowing the NPE to happen. However, there is still the possibility of unexpected NPEs as well ... depending on the code. So this approach is always potentially fragile.

(FWIW - I've never encountered a real case where this would be a good idea ...)


In many cases of catching NullPointerException, catch body only calls printStackTrace().

That is probably bad code. Doing nothing is rarely the correct way to recover from an NPE.

If I don't catch NullPointerException and call printStackTrace(), how I can check the place where the exception occurred?

You let the NPE propagate to the base level. There you catch and print (or log) a stacktrace for all unhandled exceptions, and then either bail out or attempt to recover ... if that is feasible.

And also if I catch NullPointerException and the catch body is empty, we cannot get any stack information at that time, can we?

Never, ever do this! It is called "squashing" and is dangerous. (Especially since, as I explained above, the NPE may be due to something that you / your code did not anticipate.)

And no, if you do this, you can't get the stack trace. It is gone.


FOLLOWUP

I don't place much trust / faith on some general strategies for "avoiding NPEs"1. For instance stuff like this:

return (someObject != null) ? someObject.toString() : "";

always make me suspicious that the programmer is not thinking about the problem. Why was someObject a null in the first place?

A NPE is caused by having a null in place where you don't expect it. As such, NPEs are usually symptoms of a problem rather than the actual problem itself. To my mind, NPEs are not something to be avoided. Rather, you should be using the NPEs to find and fix the root cause of the unexpected null. Code like the above that avoids the NPE gets in the way of that goal.

So I prefer / recommend strategies for avoiding null values in unexpected places.

  • Make sure that every reference field is gets initialized to a non-null value ... unless null is a meaningful value.

  • Try to avoid having null as a meaningful value, especially if there is an alternative. For instance, an empty String, a zero length array, an empty collection, a distinguished instance that means "undefined" or whatever. Or, for Java 8 and later, use Optional.

  • Don't return null as an error or an indication of a special case. (Throw an exception or return a distinguished value.)

  • Check early for unanticipated null values (e.g. null arguments), and throw the NPE sooner rather than later.

  • In the few places where a null argument or result is legitimate, make sure that your javadocs document this clearly and explicitly. If there is no documentation, then the implication should be that null is not allowed and won't be returned.

And wherever you get an NPE, make sure that you find and fix the real source of the problem ... not just the specific statement that threw the exception.

1 - There is value in knowing about places in the standard Java APIs where null is used (or abused) as a return value. For instance, Class.getResourceAsStream(...) or HttpRequest.getParam(...). Those "advice for avoiding NPE" documents are useful in as much that they point out these traps.

这篇关于什么时候可以捕获 NullPointerException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆