【问题标题】:The Cyclomatic Complexity of this method is greater than authorized此方法的圈复杂度大于授权
【发布时间】:2016-05-05 09:21:20
【问题描述】:

我正在使用以下方法来检查 null 或空字段:

public boolean isVoNotNull(){
        return null != this.cardNo &&  StringUtils.isNotBlank(this.cardNo) 
                && null != this.otp && StringUtils.isNotBlank(this.otp) 
                && null != this.password && StringUtils.isNotBlank(this.password)
                && null != this.userid && StringUtils.isNotBlank(this.userid) 
                && null != this.type && StringUtils.isNotBlank(this.type) 
                && null != this.walletMobileNo && StringUtils.isNotBlank(this.walletMobileNo);
    }

但在使用 SonarLint 验证此代码时出现异常

例外:此方法“isVoNotNull”的圈复杂度为 12 大于 10 授权。

如何解决此异常或如何消除代码的复杂性?

【问题讨论】:

  • 如果你使用的是来自 Apache 的StringUtils,那你为什么要在那里检查null

标签: java cyclomatic-complexity


【解决方案1】:

您需要分析重复的代码并将其重构为可重用的方法。

鉴于你原来的 sn-p,

public boolean isVoNotNull() {
    return null != this.cardNo &&  StringUtils.isNotBlank(this.cardNo) 
        && null != this.otp && StringUtils.isNotBlank(this.otp) 
        && null != this.password && StringUtils.isNotBlank(this.password)
        && null != this.userid && StringUtils.isNotBlank(this.userid) 
        && null != this.type && StringUtils.isNotBlank(this.type) 
        && null != this.walletMobileNo && StringUtils.isNotBlank(this.walletMobileNo);
}

我们可以识别出以下重复部分:

null != this.xxx && StringUtils.isNotBlank(this.xxx)

鉴于StringUtils#isNotBlank() already 检查null,我们可以进一步简化它。

StringUtils.isNotBlank(this.xxx)

鉴于您需要多次调用它,最好将其重构为采用variable number of arguments 的方法,该方法在循环中检查它们。

public static boolean isNoneBlank(String... strings) {
    for (String string : strings) {
        if (!StringUtils.isNotBlank(string)) {
            return false;
        }
    }
    return true;
}

或者,如果您已经在使用 Streams and Lambda 支持的 Java 8:

public static boolean isNoneBlank(String... strings) {
    return Arrays.stream(strings).allMatch(StringUtils::isNotBlank);
}

现在你可以像下面这样使用它了:

public boolean isVoNotNull() {
    return isNoneBlank(this.cardNo, this.otp, this.password, this.userid, this.type, this.walletMobileNo);
}

您可以通过删除不必要的 this 来进一步减少样板文件。

public boolean isVoNotNull() {
    return isNoneBlank(cardNo, otp, password, userid, type, walletMobileNo);
}

这一切都是Don't Repeat Yourself (DRY) 软件工程原理的应用。

也就是说,正如msandiford 指出的那样,事实证明Apache Commons Lang StringUtils 自3.2 版以来already 正是这种方法。因此,如果您还没有,请考虑将 Apache Commons Lang 升级到至少 3.2。

public boolean isVoNotNull() {
    return StringUtils.isNoneBlank(cardNo, otp, password, userid, type, walletMobileNo);
}

【讨论】:

  • 对我来说最好的答案,它表明重构过程比最终正确的代码 sn-p 更有价值
【解决方案2】:

正如其他人指出的那样,null 检查是多余的,因为 isNotBlank 也会检查这一点。

因此,如果您使用的是 Apache StringUtils 3.2 或更高版本,则可以使用 StringUtils.isNoneBlank(...)

public boolean isVoNotNull() {
    return StringUtils.isNoneBlank(cardNo, otp, password, userid, type, walletMobileNo);
}

如果您使用的是早期版本,您可以轻松编写一个:

public static boolean isNoneBlank(CharSequence... seqs) {
  for (CharSequence seq : seqs) {
    if (StringUtils.isBlank(seq))
      return false;
  }
  return true;
}

或者在 Java 8 中:

public static boolean isNoneBlank(CharSequence... seqs) {
  return Stream.of(seqs).allMatch(StringUtils::isNotBlank);
}

【讨论】:

    【解决方案3】:

    将字符串添加到数组并使用循环检查是否为空而不是空白。当然是最差的表现,但应该打破这个无意义的限制。

    示例代码:

    public boolean isVoNotNull(){
        string [] stringsToCheck = new string[]{
        this.cardNo,
        this.otp,
        // ...
        }
    
        //return CheckStringArrayNotNull(stringsToCheck);        
        return StringUtils.isNoneBlank(stringsToCheck);
    }
    
    // high chance this method already exists inside StringUtils
    // INFACT FOUND! :)
    private boolean CheckStringArrayNotNull( string [] stringsToCheck){
         for(int i=0; i<stringsToCheck.length(); i++)
            if( StringUtils.isNotBlank( stringsToCheck[i]) == false)
                return false;
    
        return true; 
    }
    

    甚至更好,(编辑:@msandiford 似乎在这个解决方案上按时击败了我)

    public boolean isVoNotNull(){      
        return StringUtils.isNoneBlank(cardNo, otp, ...);
    }
    

    您当然可以分解更多方法来降低圈复杂度,但这会使课程更难阅读和理解。代码度量应该只用于调查问题,而不是作为开发的口头禅,例如,我可以采用一个非常愚蠢的类,它有 100 个方法,每个方法的循环复杂度为 100,并对其进行重构,使其具有完美的代码度量,但无法理解。永远不要看代码指标,在不使用代码指标的情况下思考好的解决方案。

    【讨论】:

      【解决方案4】:

      StringUtils.isNotBlank

      https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#isNotBlank%28java.lang.CharSequence%29

      "检查 CharSequence 是否不为空 ("")、不为 null 且不只是空格。"

      该函数已经检查对象是否为空,那么你可以简化

      public boolean isVoNotNull() { 
        return StringUtils.isNotBlank(this.cardNo) 
            && StringUtils.isNotBlank(this.otp) 
            && StringUtils.isNotBlank(this.password)
            && StringUtils.isNotBlank(this.userid) 
            && StringUtils.isNotBlank(this.type) 
            && StringUtils.isNotBlank(this.walletMobileNo);
      }
      

      要减少条件运算符的数量,您可以执行以下操作:

      public boolean isVoNotNull(){
        Boolean[] condition = new Boolean[] {
            StringUtils.isNotBlank(this.cardNo), 
            StringUtils.isNotBlank(this.otp),
            StringUtils.isNotBlank(this.password),
            StringUtils.isNotBlank(this.userid), 
            StringUtils.isNotBlank(this.type),
            StringUtils.isNotBlank(this.walletMobileNo)
        };
        return BooleanUtils.and(condition);
      }
      

      也许有点棘手,但它有效

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-11
        • 1970-01-01
        相关资源
        最近更新 更多