一、圈复杂度概念
圈复杂度(
Cyclomatic complexity
)是一种代码复杂度的衡量标准,是一种固定的数据模型计算方式。
圈复杂度用来衡量一个模块判定结构的复杂程度,数量上表现为线性无关路径条数,即覆盖所有的可能情况、最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难以测试和维护。
1、圈复杂度计算规则
在计算圈复杂度时,可以通过程序控制流图方便的计算出来。 通常使用的计算公式是
V(G) = e – n + 2
,e
代表在控制流图中的边的数量(对应代码中顺序结构的部分),n
代表在控制流图中的节点数量,包括起点和终点(1、所有终点只计算一次,即便有多个return
或者throw
;2、节点对应代码中的分支语句)。
&&
、||
条件判断符号 +1if
、elseif
、else
、switch
分支语句 +1for
、while
、do while
循环语句 +1catch
捕获异常语句 +1break
、continue
终端语句 +1- 如果
if
、fo
r、while
、do while
、catch
存在嵌套时,里层的语句相对外层 +1
2、idea圈复杂度插件 MetricsReload
二、圈复杂度优化
1、优化表达式
针对if
、else
判断的处理,如果之后没有处理,则在if
中直接返回,else
无需使用
代码示例:
源程序:
public String testCase(String number){
String str = null;
if(StringUtils.isEmpty){
return null;
}else{
str = Integer.valueOf(number);
}
return str;
}
重构后:
public String testCase(String number){
String str = null;
if(!StringUtils.isEmpty){
str = Integer.valueOf(number);
}
return str;
}
2、提炼函数
将可以组织独立起来的代码放进一个独立函数中,并使用可以解释函数用法的函数名。
如果开发工具是idea
,可以使用Ctrl+ALT+M
快捷键直接抽取方法。
代码示例:
源程序:
void printItem(Long itemId){
// 打印大标题
System.out.println ("**************************");
System.out.println ("********** item **********");
System.out.println ("**************************");
Item item = null;
// 查询商品信息
if (null == itemId){
return;
}
item = itemService.searchItemById(itemId);
//打印详情
System.out.println ("code:" + item.code);
System.out.println ("name:" + item.name);
System.out.println ("price" + item.price);
}
重构后:
void printItem(Long itemId){
// 打印大标题
printTitle();
Item item = null;
// 查询商品信息
if (null == itemId){
return;
}
item = itemService.searchItemById(itemId);
//打印详情
printItemDetail(item);
}
void printTitle(){
System.out.println ("**************************");
System.out.println ("********** item **********");
System.out.println ("**************************");
}
void printItemDetail(Item item){
System.out.println ("code:" + item.code);
System.out.println ("name:" + item.name);
System.out.println ("price" + item.price);
}
3、简化代码[合并条件式、使用更简洁的表达]
将当前算法重构成更简洁清晰的算法
代码示例:
源程序:
public String foundNumber(String[] numbers){
for (int i = 0; i < numbers.length; i++) {
if ("One".equals(numbers[i])){
return "One";
}else if("Two".equals(numbers[i])){
return "Two";
}else if("Three".equals(numbers[i])){
return "Three";
}
}
return null;
}
重构后:
public String newFundNumber(String[] numbers){
List<String> numberList = Arrays.asList("One", "Two", "Three");
for (String number : numbers) {
if (numberList.contains(number)) {
return number;
}
}
return null;
}
4、减少认知复杂度
如果大量使用if-else
语句可以考虑用switch
代替;考虑使用return
和break
替换标记变量,提高可读性。
5、工具类替换逻辑判断
使用已有的工具类判断。判空等操作可以使用工具类,减少&&
和||
的判断使用。