Effective java recommend that we shouldn’t catch NullPointerException. Is it always right?
几乎在所有情况下都是正确的.
NullPointerException通常是一个bug的结果;即,您的应用程序在未预料到的情况下遇到空对象引用,然后尝试使用它.在这种情况下,由于您(程序员)没有预料到null,因此几乎不可能知道尝试恢复是否安全,和/或知道可能需要什么“补救”.因此,最好的办法是让NPE传播到基本级别,然后将其视为通用错误. (在“网络服务”应用程序中,可能适合返回“服务错误”响应,并尝试继续.)
另一种情况是您(程序员)预期可能会传递null.在这种情况下,最好的策略是(几乎总是)在尝试使用它之前显式测试null,从而避免NPE ……以及处理它的需要.有两个原因:
>异常处理通常很昂贵.实际上,它比测试零点要贵许多个数量级.
>如果您允许预期的NPE发生然后捕获它,您还有可能捕获其他意外的NPE ……并且错误地处理它们.
请注意,我通过说“几乎总是”来证明上述内容.从理论上讲,有一种情况可能会使null的显式测试使代码混乱,以至于至少值得考虑允许NPE发生.但是,仍然存在意外的NPE的可能性……取决于代码.所以这种方法总是很脆弱.
(FWIW – 我从来没有遇到过这个好主意的真实案例……)
In many cases of catching NullPointerException, catch body only calls printStackTrace().
这可能是糟糕的代码.无所事事很少是从NPE中恢复的正确方法.
If I don’t catch NullPointerException and call printStackTrace(), how I can check the place where the exception occurred?
您让NPE传播到基准级别.在那里你捕获并打印(或记录)所有未处理异常的堆栈跟踪,然后挽救或尝试恢复……如果这是可行的.
And also if I catch NullPointerException and the catch body is empty, we cannot get any stack information at that time, can we?
永远不要这样做!它被称为“挤压”并且很危险. (特别是因为,正如我上面所解释的那样,NPE可能是由于你/你的代码没有预料到的.)
不,如果你这样做,你就无法获得堆栈跟踪.它消失了.
跟进
我对“避免NPEs”的一些一般策略没有太多的信任/信心1.例如这样的东西:
return (someObject != null) ? someObject.toString() : "";
总是让我怀疑程序员没有考虑这个问题.为什么someObject首先是null?
NPE是由于在您不期望它的位置存在空值而引起的.因此,NPE通常是问题的症状,而不是实际问题本身.在我看来,NPE不是一个值得避免的东西.相反,您应该使用NPE来查找并修复意外null的根本原因.像上面那样避免NPE的代码妨碍了这个目标.
所以我更喜欢/建议在意外的地方避免空值的策略.
>确保将每个引用字段初始化为非空值…除非null是有意义的值.
>尽量避免将null作为有意义的值,尤其是在有替代方法的情况下.例如,一个空字符串,一个零长度数组,一个空集合,一个表示“未定义”或其他的可分辨实例.或者,对于Java 8及更高版本,请使用Optional.
>不要将null作为错误或特殊情况的指示返回. (抛出异常或返回一个值.)
>提前检查未预料到的空值(例如空参数),并尽快抛出NPE.
>在null参数或结果合法的少数几个地方,请确保您的javadocs清楚明确地记录了这一点.如果没有文档,那么暗示应该是不允许null并且不会返回.
无论你在哪里获得NPE,都要确保找到并修复问题的真正根源……而不仅仅是抛出异常的特定语句.
1 – 了解标准Java API中使用null(或滥用)作为返回值的位置是有价值的.例如,Class.getResourceAsStream(…)或HttpRequest.getParam(…).这些“避免NPE的建议”文件在指出这些陷阱方面非常有用.