Sonar 如何计算圈复杂度?

问题描述 投票:0回答:2

声纳给我以下圈复杂度数:22。

对于以下程序:

private static SomeDto checkSomething(AnotherDto anotherDto, String reference)
{
SomeDto someDto = new SomeDto();

// condition 1
if (!someDto.getA())
    return new SomeDto("bla1", "blabla");

// condition 2
if (someDto.getName2() == null || checkSurName(anotherDto.getName()))
    return new SomeDto("bla2", "blabla");

// condition 3
if (someDto.getName3() == null || checkSurName(anotherDto.getName()))
    return new SomeDto("bla3", "blabla");

// condition 4
if (someDto.getName4() == null && checkSurName(anotherDto.getName()))
    return new SomeDto("bla4", "blabla");

// condition 5
if (someDto.getName5() == null || checkSurName(anotherDto.getName()))
    return new SomeDto("bla5", "blabla");

// condition 6
if (someDto.getName6() == null && checkSurName(anotherDto.getName()))
    return new SomeDto("bla6", "blabla");

// condition 7
if (someDto.getName7() == null && checkSurName(anotherDto.getName()))
    return new SomeDto("bla7", "blabla");

// condition 8
if (someDto.getName8() == null && checkSurName(anotherDto.getName()))
    return new SomeDto("bla8", "blabla");

// condition 9
if (someDto.getName9() == null && checkSurName(anotherDto.getName()))
    return new SomeDto("bla9", "blabla");

// condition 10
if (someDto.getName10() == null && checkSurName(anotherDto.getName()))
    return new SomeDto("bla10", "blabla");

// condition 11
if (someDto.getName11() == null && checkSurName(anotherDto.getName()))
    return new SomeDto("bla11", "blabla");

return someDto;
}    

我遇到的问题如下:

“此方法“checkSomething”的循环复杂度为 22,大于授权的 12。

我的问题是: 考虑到 McCabe 公式 V(G) = E - N + 2,Sonar 的数量是如何达到 22 的?

哪里:

E = 边数

N = 节点数

该方法有多少条边和节点? 该方法的控制流程是什么?

我们使用 SonarQube 版本 6.3(内部版本 19869)。

java sonarqube graph-theory checkstyle cyclomatic-complexity
2个回答
8
投票

SonarQube 最新版本的文档清楚地说明了它如何计算圈复杂度:

Complexity(复杂度)是计算出的Cyclomatic Complexity 基于代码的路径数。每当控制 函数流分裂,复杂度计数器增加 一。每个函数的最小复杂度为1。这个计算 由于关键字和功能不同,因此语言略有不同。

如果您打开该段落下方的“特定于语言的详细信息”,Java 行将显示如下。

增加复杂性的关键字:if、for、while、case、catch、 抛出,&&,||,?

由于OP在提出问题时使用的是6.3版本,我还检查了我能找到的最旧版本的文档(不再可用),即6.7。到那时,计算略有不同。

增加复杂性的关键字:if、for、while、case、catch、 throw、return(这不是方法的最后一条语句)、&&、||、?

备注:

else、default 和finally 关键字不会增加复杂性。

一个带有 switch 语句和大量 case 的简单方法 语句可能具有令人惊讶的高复杂度值(仍然有 将开关块转换为等效块时的相同值 if 语句的序列)。

示例:以下方法的复杂度为 5

public void process(Car myCar){          // +1
    if(myCar.isNotMine()){               // +1
         return;                         // +1
    }
    car.paint("red");
    car.changeWheel();
    while(car.hasGazol() && car.getDriver().isNotStressed()){   // +2
         car.drive();
    }
    return; }

1
投票

好吧,经过进一步调查并根据这个link(checkstyle工具),我得出的结论是McCabe公式并没有真正应用于计算Java程序中的圈复杂度。

复杂度等于决策点的数量 + 1 决策点: if、 while 、 do、 for、 ?:、 catch 、 switch、 case 语句以及运算符 && 和 ||在目标体内。

因此,如果我将此规则应用于之前的示例代码:

private static SomeDto checkSomething(AnotherDto anotherDto, String reference)  // 1
{
SomeDto someDto = new SomeDto();

// condition 1
if (!someDto.getA())                                                             // 2
return new SomeDto("bla1", "blabla");

// condition 2
if (someDto.getName2() == null || checkSurName(anotherDto.getName()))             // 4
return new SomeDto("bla2", "blabla");

// condition 3
if (someDto.getName3() == null || checkSurName(anotherDto.getName()))             // 6
return new SomeDto("bla3", "blabla");

// condition 4
if (someDto.getName4() == null && checkSurName(anotherDto.getName()))             // 8
return new SomeDto("bla4", "blabla");

// condition 5
if (someDto.getName5() == null || checkSurName(anotherDto.getName()))              // 10
return new SomeDto("bla5", "blabla");

// condition 6
if (someDto.getName6() == null && checkSurName(anotherDto.getName()))              // 12
return new SomeDto("bla6", "blabla");

// condition 7
if (someDto.getName7() == null && checkSurName(anotherDto.getName()))              // 14
return new SomeDto("bla7", "blabla");

// condition 8
if (someDto.getName8() == null && checkSurName(anotherDto.getName()))              // 16
return new SomeDto("bla8", "blabla");

// condition 9
if (someDto.getName9() == null && checkSurName(anotherDto.getName()))              // 18
return new SomeDto("bla9", "blabla");

// condition 10
if (someDto.getName10() == null && checkSurName(anotherDto.getName()))             // 20
return new SomeDto("bla10", "blabla");

// condition 11
if (someDto.getName11() == null && checkSurName(anotherDto.getName()))             // 22
return new SomeDto("bla11", "blabla");

return someDto;
}    

如果我错了,请纠正我。 难道不应该至少考虑 return 语句(除了该方法的最后一个语句)吗?

无论如何,结果数字 22 是有道理的。该方法有大量连续的“if”条件,应该对此采取措施以提高其可维护性。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.