如何在首先检查结果为null时避免冗余方法调用?

时间:2018-06-18 10:50:36

标签: java

我在代码中找到了areoccuring模式,我多次调用相同的方法:

private String doSomething(MyObject obj) {
   if (myObj == null
      || myObj.getA() == null
      || myObj.getA().getB() == null
      || myObjg.getA().getB().getC() == null) {
         throw new IllegalArgumentException("Error message...");
   } else {
      return myObj.getA().getB().getC();
   }
}

如您所见,我多次调用getA(),getB()和getC()。我想避免这种情况,但仍然检查是否为null。什么是避免这些冗余方法调用的好方法?

4 个答案:

答案 0 :(得分:4)

从技术上讲,你不必担心反复调用这些getter方法。 getter应该是真正小方法,所以 JIT在运行时认为值得优化它们时,无论如何它们都会在机器代码中内联,从而为您提供最大的性能。当JIT发现"这不值得优化",然后猜测:然后不值得优化。如果你的getter方法太大而无法内联,那么无论如何你都会遇到真正的问题。

但真正的答案是:首先不要违反Law of Demeter

允许这种类型的改变是不好的做法。您提交的代码知道 A有B有C。因此,此代码依赖于三个类A,B,C。您的A和B类可以& #39;如果没有破坏客户端,请更改。从这个角度来看,这种"流利的"应该避免使用接口getA().getB().getC().doSomething()

这里真正的答案是将doSomething()放在A类上,隐藏背后的所有潜在依赖关系。

答案 1 :(得分:4)

Optional,尤其是map()方法,非常适合这种情况:

private String doSomething(MyObject obj) {
    return Optional.ofNullable(myObj)
        .map(MyObject::getA)
        .map(MyObject::getB)
        .map(MyObject::getC)
        .orElseThrow(() -> new IllegalArgumentException("Error message..."));
}

答案 2 :(得分:1)

这种“模式”不是问题。这是问题的症状真正的问题是您编写的代码基于使用包含可连接字段链的过程数据持有者。

然后,解决方案是编写代码that uses proper objects

答案 3 :(得分:0)

我对您的模式的首选替代方法是在每个访问阶段明确检查。这导致更加丰富和更详细的错误管理,代价是一些额外的缩进。

private String doSomething(MyObject myObj) {
    if(myObj != null) {
        A a = myObj.getA();
        if(a != null) {
            B b = a.getB();
            if(b != null) {
                return b.getC();
            } else {
                throw new IllegalArgumentException("myObj.a.b is null");
            }
        } else {
            throw new IllegalArgumentException("myObj.a is null");
        }
    } else {
        throw new IllegalArgumentException("myObj is null");
    }
}

请注意,if形状的这种深度嵌套被认为是箭头反模式的症状,这通常表示您应该进行一些重构。请记住,这只是该问题的指标,它不是问题本身。