Java 中的循环复杂度

Java 中的代码管理是一个人们可能熟悉的概念。它涉及如何组织源代码,以便在维护期间处理它可以更加简单。除了其他时间复杂度之外,该圈复杂度是根据程序的控制流计算的。

例如:如果一个程序没有控制语句,那么该程序的圈复杂度被认为是1。

圈复杂度公式
一般来说,计算圈复杂度的公式为:
圈复杂度 = 总决策点数 +  1  

让我们看看各种例子并计算它的圈复杂度。
示例 - 1

public class CyclomaticComplexity1   
{  
// method foo  
void foo()  
{  
int y = 0;  
if (true && false)  
{  
y = 1;  
}  
else  
{  
y = 2;  
}  
System.out.println(
"Inside the foo method.");  
}  
// main method  
public static void main(String argvs[])   
{  
//将 CyclomaticComplexity1 类实例化;
CyclomaticComplexity1 obj = new CyclomaticComplexity1();  
obj.foo();  
}  
}  

分析该程序有一个决策点,即 if 条件,因此应用循环复杂度的公式,我们可以得到该程序的循环复杂度:

循环复杂度 = 1 + 1 = 2

2表实有两个控制流。一个流经 if 语句的主体,另一个流经 else 块。

示例2:

public class CyclomaticComplexity2   
{  
void foo()  
{  
int y = 0;  
// first - if  
if(true)  
{  
System.out.println(
"Inside the first if-condition.");  
}  
// second - if  
if (true && false)  
{  
y = 1;  
System.out.println(
"Inside the second if-condition.");  
}  
// else block  
else  
{  
y = 2;  
}  
  
System.out.println(
"Inside the foo method.");  
}  
// main method  
public static void main(String argvs[])   
{  
// instantiating the class CyclomaticComplexity2  
CyclomaticComplexity2 obj = new CyclomaticComplexity2();  
obj.foo();  
}  
}  

分析在上述情况中,决策点的数量为 3 个。因此,根据公式,我们可以得到如下的循环复杂度:

循环复杂度 = 3 + 1 = 4。

4 意味着有四个控制流。

  1. 第一条流经第一个 if 语句的主体,然后流经第二个 if 语句的主体。
  2. 第二个流经第一个 if 语句的主体,然后是 else 块。
  3. 第三个流经第二个 if 语句的主体,
  4. 第四个流经 else 块。

示例3:

public class CyclomaticComplexity3  
{     
void foo()  
{  
String n = "a";  
String n1 =
"b";  
String n2 =
"c";  
int age = 12;  
  
// if-condition  
if( n.equals(n1) || n.equals( n2 ) || n1.equals(n1) && age != 23 )  
{  
System.out.println(
"Inside the if condition.");  
}  
  
System.out.println(
"Inside the foo method.");  
}  
  
// main method  
public static void main(String argvs[])   
{  
// instantiating the class CyclomaticComplexity3  
CyclomaticComplexity3 obj = new CyclomaticComplexity3();  
obj.foo();  
}  
}  

分析在上述情况下,循环复杂度可计算为决策点总数加逻辑运算符总数加 1。由于只有一个 if 条件,因此只有一个决策点。另外,有三个逻辑运算符,两个 || 和一个 &&。因此,循环复杂度可计算为

循环复杂度 = 1 + 3 + 1 = 5

这意味着有五个控制流。

  1. 一个是当 n.equals(n1) 为真时,执行 if 条件的主体。
  2. 第二个是当 n.equals(n1) 为假,n.equals(n2) 为真时,执行 if 条件的主体。
  3. 第三种情况是,n.equals(n1) 为假,n.equals(n2) 也为假,逻辑 && 为真,if 条件的正文执行。
  4. 第四种情况是 n.equals(n1) 为假,n.equals(n2) 也为假,而 && 运算符的第一个操作数也为假,if 条件的正文不执行。
  5. 最后也是第五种情况是:n.equals(n1) 为假,n.equals(n2) 也为假,&& 操作符的第一个操作数为真,但第二个操作数为假,if 条件的正文不执行。

各种决策点
有多种决策点会影响圈复杂度 

  • ||  和 &&
  • for, do, while
  • ?: (三元操作), if-else
  • Switch, case statements, catch.

开发人员或程序员应该以降低圈复杂度的方式编写代码。
降低环复杂度的好处
以下是降低圈复杂度的一些好处。

  • 代码的耦合度降低了。圈复杂度的值越高,代码的耦合性就越大。高耦合代码的缺点是不易修改。
  • 当圈复杂度增加时,理解代码的难度也会增加。这是因为控制路径的数量也增加了,这可能会导致更多意想不到的结果。
  • 较高的圈复杂度意味着需要测试的情况较多。例如,如果某个方法的圈复杂度为 12,则意味着该方法有 12 条独立路径,并且需要探索所有这 12 条路径。因此,降低圈复杂度意味着减少测试用例,使软件或程序的测试变得容易。

计算圈复杂度的工具
以下是计算圈复杂度的工具。

  • Findbugs
  • Checkstyle
  • Sonar
  • Cobertura
  • Jarchitect

在代码的构建生命周期中,可以合并这些工具。

圈复杂度的优点和缺点
在本教程中,我们将讨论圈复杂度的优缺点。我们先从优点说起。
优点

  • 考虑到不同设计的相对复杂性,可以利用循环复杂性作为质量度量。
  • 它还可以用作最小工作量和测试重点的适当领域的衡量标准。
  • 易于申请
  • 提供测试指导

缺点
  • 圈复杂度仅提供有关控制流复杂度的信息,而不提供有关时间相关复杂度的信息。
  • 在这种复杂性中,与非嵌套条件相比,嵌套条件更难解读。
  • 即使在简单的决策结构和比较的情况下,它也可能给出一个具有误导性的数字。

圈复杂度的使用
以下是圈复杂度的用法。

  • 循环复杂度决定了对测试人员和开发人员有帮助的独立路径执行的数量。
  • 它确保每条路径至少被验证一次。
  • 它有助于关注未发现的路径。
  • 评估与该计划相关的风险。
  • 代码覆盖率的改进。