在Java中,有没有更简单的方法来取消引用可空引用?

4

请看下面的代码片段:

if (foo != null
 && foo.bar != null
 && foo.bar.boo != null
 && foo.bar.boo.far != null)
{
    doSomething (foo.bar.boo.far);
}

我的问题很简单:是否有更简单/更短的方法来做到这一点?
具体来说,是否有更简单的方法来验证链中的每个部分,我想象类似于这样...
if (validate("foo.bar.boo.far"))
{
    doSomething (foo.bar.boo.far);
}

6
请参阅“迪米特法则”(The law of demeter)… - Mitch Wheat
尝试执行{doSomething(foo.bar.boo.far);},但是catch(NullPointerException e){}不算吧?:) - makasprzak
可能取决于 null 条目有多常见,否则会非常快地变得昂贵。 - Richard Tingle
你的第一个片段清晰明了,简洁明了。如果你确实需要将四个嵌套对象与null进行比较,那么没有比这更简单的方法了。第二个片段中有字符串代码,令人感到害怕。这并不是一种改进。 - Joshua Barr
6个回答

5
也许是这样吗?
if (FooUtils.isFarNotEmpty(foo)){
    doSomething (foo.bar.boo.far);
}

而在 FooUtils 中:

boolean isFarNotEmpty (Foo foo){
   return foo != null && 
          foo.bar != null && 
          foo.bar.boo != null && 
          foo.bar.boo.far != null;
}

1
我差不多要写同样的回答了 :), 名字也几乎一样!! - Grijesh Chauhan
@JoshuaBarr 它正在使用实用类模式。 - Khaled.K
将丑陋的代码放在一个方法中可能会稍微提高可读性,但这只是掩耳盗铃。像这样隐藏有问题的代码只是回避了它的根本原因。它仍然应该让你感到不舒服。 - Joshua Barr
@JoshuaBarr 随着时间的推移,你会学会,总有人得做一些肮脏的工作...但是请检查我下面添加的解决方案,这是一位软件工程师的建议。 - Khaled.K

2
在我看来,这个表达完美无缺,再也没有什么更简单易懂的了。

我不同意。这比任何人想要的都更冗长,写起来很繁琐,而且维护起来也很麻烦。虽然在Java中这已经是最好的选择了,但它真的很难看。 - Daniel Kaplan
@tieTYT,你的解决方案使用异常来控制流程,我认为这比有点啰嗦要糟糕得多。try/catch不应该替代if语句。 - Joshua Barr
@JoshuaBarr 1) 这不是为什么这个表达式完美的理由。2) 总的来说我同意,但我觉得我给出了一个值得违反的理由。如果你不同意这个理由,请告诉我为什么。 - Daniel Kaplan
@tieTYT 我认为大多数人都会同意这样奇怪的if语句是一个更大问题的症状。但考虑到限制条件,if语句似乎是最好的选择。我给出了我对此信仰的理由(不要使用异常来控制流程),但这显然是主观的。 - Joshua Barr
1
@tieTYT,另外,像你这样捕获NullPointerException是有问题的,因为它会捕获doSomething抛出的NPE,这不是预期的效果。 - Joshua Barr
显示剩余3条评论

1
为什么要使用公共实例变量?封装您的公共变量并为它们创建getter和setter,您可以在getter中执行这些检查,如果它们中的任何一个为null,则可以返回新的Object(),或者您可以在try-catch块中运行此语句,但不建议这样做。

如果链条中的任何一部分为空,我就不想执行doSomething()函数。 - Khaled.K
由于NullPointerException是RuntimeException的一种,它们不应该被捕获,尽管这会缩短您的代码,但这是不好的实践和违反标准的。您发布在代码中的代码很好,可以继续使用。 - Yahya Arshad
为什么我需要抛出一个异常,当我已经在尝试避免它?我的代码是好的,但我希望有一种更简洁的方式。 - Khaled.K
请再次阅读我的帖子,我已经提到捕获RuntimeException不是一个好的做法。 - Yahya Arshad

1

如果这是您的API,请考虑一些建议

“我称之为我的十亿美元错误。”- C. A. R. Hoare爵士,谈论他发明的空引用


你永远不能确定它不会是null。 - Khaled.K
在这个模型中,每个空指针都是一个错误。基于这个假设,您可以再次信任您的类型系统,确保类型A确实是A而不是null。 - Thomas Jung
你知道为什么NullPointerException是一个运行时异常吗?因为在执行代码之前你永远不知道它是否会发生。 - Khaled.K
我认为这是一个运行时异常,因为试图取消引用 NP 是程序员的错误。如果允许空值,则是用户错误;如果不允许,则是返回空值的代码错误。 - Thomas Jung
你假设我是如何处理上下文的,以便我可以放置那个例子...事实是,我正在处理一个企业系统,这个系统在我加入之前就已经建立了,而且我所处理的系统使用数据库,并且依赖于数据,这些数据有无限的可能性会导致业务逻辑出错,但我的工作并不是检查所有的问题。 - Khaled.K

0

很遗憾,你不能做太多事情。如果问我,这是Java语言的问题。Groovy有一个叫做安全导航运算符?.的东西,专门用于此目的。以下是我过去做过的两件事。

  1. Grisha已经给出了答案,我就不重复了
  2. 天真地编写了访问它的代码,并在try/catch中包围了一个NPE。以下是一个例子:

    try {
        if (foo.bar.boo.far != null) {
            //做一些事情
        }
    } catch (NullPointerException e) {
        //执行else中的操作
    }
    

我并不特别喜欢第二个选项,但如果它确实可以使代码更清晰,考虑使用它。

有一次我在使用一个非常薄的库来包装XML模式,我决定在这种情况下使用第二个选项。如果我不这样做,代码将会更难维护,因为很容易忘记空值检查并且它们会混淆重要的逻辑。我认为这是使用它的一个有效案例。


我正在尝试避免在链的任何部分为NULL的情况下执行doSomething(),因为针对这种可能性引发异常会使您的代码比我的示例更糟糕。 - Khaled.K
在我的代码中,如果任何一个链为空,你就不会调用 doSomething()。如果这是你的代码中唯一有这样一个 if 语句的地方,那么我不建议使用第二种方法。但是,如果你的代码到处都是这样的代码,就像我一样,那么使用第二种方法可能会使你的代码更加简洁。 - Daniel Kaplan
但是,如果当我已经计划避免异常时仍然抛出异常,那就很尴尬了。 - Khaled.K

0
请尝试这段代码。
try {
    if (foo.bar.boo.far != null) {
        //No object is null
    }
} catch (Exception e) {
    // some object is null and causes null point exception.
}

抱歉,如果当我已经计划避免异常时仍然发生异常,那就很尴尬。 - Khaled.K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接