编写代码而不使用null

时间:2015-09-08 17:38:55

标签: java android

在Java中,默认情况下,对象初始化为null

我最近在研究正确处理NPE时遇到了这个答案:https://softwareengineering.stackexchange.com/a/187225

以下是我从帖子中获得的主要内容:

  

如果您从未将变量设置为null,则永远不会出现意外的空值。

     

不允许空参数

我一直想知道如何在Java和Android中处理这个问题。我在开发人员信息中心看到的许多崩溃报告都是NPE,我注意到在我的代码中,我使用null检查是否可以继续操作。

我正在梳理我的代码库,尝试尽可能删除null和默认实例化,但我遇到了出现的几个区域而且我不确定如何解决这些变量引起的错误。

例如,使用Google Maps API时,您必须声明GoogleMap个对象。我目前设置的方式是将变量声明为Activity的成员,然后在onCreate()期间初始化它。不幸的是,在我onResume().clear() GoogleMap时,有时候该字段将为null。我无法在自己的环境中重现此错误,这使我更多地阅读了处理NPE的内容。

在另一个(非常受欢迎的)问题中:Avoiding != null statements,顶部和接受的答案推荐了三种解决此问题的策略。

  1. assert声明。从表面上看,这看起来更像是单元测试/调试代码,特别是因为默认情况下Java忽略了assert
  2. 空对象模式。这可能是最具吸引力的解决方案,因为它最终看起来更清晰。但是,在使用外部库时,我不确定这是一个选项。扩展外部库似乎很麻烦。
  3. try / catch。这很难。由于null在Java中是如此普遍,因此代码最终将密集地使用try / catch来处理可能为null的所有内容,或者最终阻塞了大量代码,从而捕获了不允许的错误处理后果的准确性很高。
  4. 我的问题是,还有其他选择吗?也许我可以使用的编码范例或某种内置可能会解决这个问题?

    最理想的情况是,我想要一个解决方案,我不会崩溃,丢失数据可靠性或丢失应用程序功能。

    注意 - 这不是关于我的代码问题的问题,这是一个关于如何防御性地编写代码以防止在默认初始化为null的语言中出现意外NPE的问题

3 个答案:

答案 0 :(得分:0)

我发现引用文章的前提是例外。它声明:

  

错误,其中NullPointerException被抛出,错误位于您的代码中,其中变量设置为{{ 1}}没有你期待它。

我说错误并不期望该值为null,因此错误正是NPE发生的地方。

与任何其他工具一样,它的使用方式最重要。使用null值表示无值是完全正确的,只要它是明确定义的。

也就是说,null过度使用,并且有时应该被异常替换。但这一切都取决于具体情况。

查看Java中的BlockingQueue接口。要从队列中删除值,您可以调用null如果队列为空则抛出异常,或者您可以调用返回remove()的{​​{1}}。如果您期望值,请使用poll()。如果您知道队列可能为空,并且您将处理该队列,请使用null。不要将remove()与try-catch一起用于流量控制。

答案 1 :(得分:0)

我向自己问了同样的问题,并最终抛出异常并将其缓存在我的代码的顶层。这样做,我只需要在没有条件的情况下宣布try catch一次。当然,它需要确保如果某些值不存在或无效,则抛出异常:

    bool isEquals(string name)
    {
      if(tempData == name.toUpperCase()) // if name is null,a null reference will be throw

       //...
    }

即使你没有摆脱NPE并尝试/捕获,你可以放心应用失败的地方,这是一个很大的优势。

答案 2 :(得分:0)

Null,其本身并不是可以避免的东西。任何尚未分配和成功编译的声明引用在Java中都被视为空,原因很简单:堆上有垃圾值。 Java会跟踪您的分配,并在仍为应用程序分配了该堆块时的垃圾值的内存位置返回null。它会阻止你获取整数这样的东西的价值,认为它们属于你,当它们真的被遗留在应用程序启动之前碰巧使用相同地址的其他应用程序时。

列出的每个策略都有自己的用途,没有一个是处理可能的NPE的全部。

断言通常是应该避免的。如果条件不满足,则会导致暂停声明。换句话说,它并不是一个优雅的退出。一个!= null语句实现与断言相同的目标,但可以选择响应条件而不是暂停程序。

在遇到竞争条件的情况下,try / catch功能强大。在调用大量使用网络相关操作的异步库和库时,这尤其有用。 GoogleMaps有许多方法可以根据新的位置或视图框架获取更新的信息,在某些情况下,您可能会尝试对可能处于刷新中期的库管理的对象进行调用。当我无法轻易复制NPE时,我通常会假设竞争条件。

最后,我没有看到试图避免!= null检查的任何价值。它捕获并允许您响应try / catch不适合的所有条件,并且不需要任何费用。所有布尔运算都是O(1)运算。你必须背靠背地使用十亿或更多,以便看到甚至1秒的性能下降。不值得头痛消除。