首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不使用null编写代码

不使用null编写代码
EN

Stack Overflow用户
提问于 2015-09-08 17:38:54
回答 4查看 224关注 0票数 1

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

最近,我在研究如何正确处理NPE时发现了这个答案:https://softwareengineering.stackexchange.com/a/187225

以下是我的主要职务:

如果从未将变量设置为null,则永远不会有意外的null。 不允许空参数

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

我正在梳理我的代码库,试图尽可能地删除null和默认实例化,但是我遇到了一些不可能的地方,我不知道如何修复这些变量产生的错误。

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

在这里的另一个(非常流行的)问题:Avoiding != null statements,顶部和公认的答案推荐了三种策略来解决这个问题。

  1. assert语句。表面上看,这更像是单元测试/调试代码,特别是因为Java默认忽略assert
  2. 空物体模式。这可能是最有吸引力的解决方案,因为它最终看起来和感觉更干净。但是,在使用外部库时,我不确定这是一个选项。扩展外部库似乎很麻烦。
  3. 尝试[抓住]这太难了。由于null在Java中是如此普遍,所以代码最终会被大量尝试/捕捉到所有可能为空的代码,或者导致大量代码被封锁,这样捕获错误将不允许在处理后果时有多大的精确性。

我的问题是,还有别的选择吗?也许我可以使用一种编码范式,或者某种内置的可以解决这个问题的方法?

最理想的是,我希望有一种解决方案,使我不会崩溃、失去数据可靠性或失去应用程序功能。

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-09-08 18:12:08

Null本身并不是可以避免的。在Java中,任何尚未分配并成功编译的声明引用都被视为空引用,理由很充分:堆中有垃圾值。Java跟踪您的赋值,并在内存位置返回null,这些内存位置仍然包含应用程序分配堆块时的垃圾值。它阻止您获取整数之类的值,认为它们属于您,而实际上它们是在应用程序启动之前使用相同地址的其他应用程序遗留下来的。

列出的每一种策略都有其各自的用途,而且没有一种是处理可能的NPE的全部问题。

断言通常是要避免的。如果不满足条件,则会导致暂停语句。换句话说,这不是一个优雅的退出。A !=null语句实现了与assert相同的目标,但使用了响应条件而不是停止程序的选项。

在遇到竞赛条件的情况下,try/catch非常强大。这在调用大量使用网络依赖操作的异步库和库时尤其有用。GoogleMaps有许多基于新位置或视图框架获取更新信息的方法,在某些情况下,您可以尝试对一个由库管理的对象进行调用,该对象可能是中间刷新的。当我很难复制一个NPE的时候,我通常会假设一个比赛条件。

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

票数 0
EN

Stack Overflow用户

发布于 2015-09-08 17:49:11

我真的不明白为什么空检查被认为是不好的,对于防止顶级异常使用@NonNull@Nullable注释,静态分析确实有帮助。

票数 1
EN

Stack Overflow用户

发布于 2015-09-08 18:09:43

我发现对所引用的文章的前提有异议。它指出:

错误不是抛出NullPointerException,而是代码中的早期bug,其中一个变量被设置为null,而您并没有预料到它会出现。

我想说的是,错误并不是期望值是null,所以错误正好发生在NPE发生的地方。

与任何其他工具一样,最重要的是如何使用它。使用一个null值来表示没有值是完全正确的,只要它是定义良好的。

尽管如此,null确实被过度使用,有时应该用异常替换。但这一切都取决于环境。

看一下Java中的BlockingQueue接口。要从队列中删除一个值,可以调用remove(),如果队列为空,可以调用它引发异常,或者调用返回nullpoll()。如果您希望得到一个值,请使用remove()。如果您知道队列可能是空的,并且您将处理该队列,请使用poll()。不要将remove()与试图捕获一起用于流控制。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32464014

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档