嵌套的 if-object-null-return 方法提取或替代声纳认知复杂性

Nested if-object-null-return method extraction or alternative for sonar cognitive complexity

在大多数情况下,当一个对象是可选的时,可以使用 Guava 来帮助进行 if null 检查。但是在语句用于决定方法是否更早 return 的情况下(根据我的经验),即使这样也是不够的。

我的问题是使用嵌套的 if 语句 return 默认值而不是继续执行方法。

这是我的意思的一个例子:

private MyObject myMethod(Object object, Object object1, Object object2) {

    /* inherent implementations for first if-statement... */
    if (object == null) {

        /* inherent implementations for second if-statement... */
        if (object1 == null) {
            return new MyObject();
        }

        /* inherent implementations for third if-statement... */    
        if (object2 == null) {
            return new MyObject();
        }

    } else {

        /*same structure shown in if-statement...*/

    }

    /* inherent implementations before last return statement... */

    return new MyObject(/* with args */);

}

我正在寻找解决认知复杂性问题的解决方案 sonarQube,其中方法中使用的 'if' 和嵌套 'if' 语句的数量增加了代码的复杂性。

换句话说,将方法中的语句提取到另一个方法中或通过不涉及 if 语句的其他方法解决它们的方法。

EDIT(05/09):首先,感谢您提供的所有答案,但我相信有一些细节我忘了提及。我提供的代码片段中提到的每个 /* implementations... */ 都有某种类型的功能,必须在下一个 if 语句之前完成,因此像 if (object1 == null || object2 == null) 这样的建议是不行的。关于使用 Java 9 的 Optional.or 的建议:据我所知,Java 8 是目前最稳定的 Java 版本,所以最坏的情况我不得不wait for Java 11. 此外,提到的每个 /* implementations... */ 都必须按顺序执行,所以为了使每个细节更加明确,我修改了一些我之前提供的代码片段.

从干净代码的角度回答:

  • 不要争论那么多。一开始听起来很傻,但是:真正的答案是设计采用尽可能少的参数的接口。因此,与其将 a、b、c 作为参数传递,不如在它们周围创建一个 class。这为您提供了更多选项来考虑默认值等。
  • 当然早returns也是可以的

您的代码显示 same structure as shown in if statement。那么简单的解决方案就是做

if (object1 == null) return new MyObject();
if (object2 == null) return new MyObject();

一次,在任何其他代码之前。重点是避免条件的嵌套。当你只是重复条件时,把它们放在不同的地方,避免重复。

要检查您的某些参数是否为空,您可以创建这样的方法:

public boolean hasNull(Object... objects) {
    return Arrays.stream(objects).anyMatch(Objects::isNull);
}

现在您可以检查任意多的参数:

private MyObject myMethod(Object object, Object object1, Object object2, Object object3, Object object4) {

    if (hasNull(object1, object2, object3, object4)) {
        return new MyObject();
    }

    /* implementations... */

    return new MyObject(/* with args */);

}