Sonar代码扫描常见问题
Use try-with-resources or close this "BufferedOutputStream" in a "finally" clause.
参考:https://blog.csdn.net/libusi001/article/details/103848922
解决方法: 在finally中关闭FileInputStream,主要是关闭方式不对,finally代码块中,应该要对每个stream进行单独关闭,而不能统一写在一个try-catch代码中。
A NullPointerException might be thrown as ‘XXX’ is nullable here.
空指针,解决方式:先判断或者先实例化,再访问里面的属性或者成员。
Use a “double” or “BigDecimal” instead.
说明:两个float计算会产生不精确的结果
解决方案:将float换为double或者BigDecimal计算
举例:
float a = 16777216.0f;
float b = 1.0f;
float c = a + b; // Noncompliant; yields 1.6777216E7 not 1.6777217E7
double d = a + b; // Noncompliant; addition is still between 2 floats
换为
float a = 16777216.0f;
float b = 1.0f;
BigDecimal c = BigDecimal.valueOf(a).add(BigDecimal.valueOf(b));
double d = (double)a + (double)b;
Cast one of the operands of this multiplication operation to a “long”
说明:int数运算最终再把结果转为long将有可能产生溢出
解决方案:转换为long型预算
举例:
long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647
换为
long bigNum = Integer.MAX_VALUE + 2L;
Close this “XXX”.
说明:流没有显示的关闭。
解决方案:在fianlly语句块内关闭。
Remove or correct this useless self-assignment.
说明:缺少this
解决方案:用this.xxx=xxx来替代
举例:
public void setName(String name) {
name = name;
}
换为
public void setName(String name) {
this.name = name;
}
Correct this “&” to “&&”.
说明:错误的使用&和&&
解决方案:根据情况使用&和&&
This branch can not be reached because the condition duplicates a previous condition in the same sequence of “if/else if” statements
说明:if else if 语句判断条件重复
解决方案:去掉多余的判断条件
Make this “XXX” field final.
说明:将某个字段置为final,常见在Exception的参数
解决方案:将字段置为final
Remove this call to “equals”; comparisons between unrelated types always return false.
说明:去掉equals判断语句,因为总为false
解决方案:去掉equals语句
Remove this return statement from this finally block.
说明:在finally语句块中有return语句
解决方案:去掉finally语句块的return语句或者放在finally语句块之外
Remove this continue statement from this finally block.
说明:在finally语句块中有continue语句
解决方案:去掉finally语句块中的continue语句或者放在finally语句块之外
Equality tests should not be made with floating point values.
说明:浮点数之间用 == 来比较大小不准确
解决方案:用Number或者BigDecimal来比较
举例:
float myNumber = 3.146;
if ( myNumber == 3.146f ) { //Noncompliant. Because of floating point imprecision, this will be false
// …
}
if ( myNumber != 3.146f ) { //Noncompliant. Because of floating point imprecision, this will be true
// …
}
Add a type test to this method.
说明:强转前未判断类型
解决方案:强转前先判断类型
举例:
ErpVO ev = (ErpVO) obj;
return this.userCode.equals(ev.getUserCode());
换为
if (obj == null) {
return false;
}
if (obj.getClass() != this.getClass()) {
return false;
}
…
Add an end condition to this loop.
说明:没有退出条件
解决方案:根据情况来决定方法的退出条件
Make “XXX” an instance variable.
说明:有些类不是线程安全的,将变量生命为静态的可能会导致线程安全问题
解决方案:将变量声明为实例的。
Strings and Boxed types should be compared using "equals()"
字符串和包装类型对比时应该使用equals方法。
解释
使用引用相等==或!=比较java.lang.String或包装类型(如java.lang.Integer)的两个实例几乎总是false,因为它不是在比较实际值,而是在内存中的位置(地址)。
在Java 中包装类型与基本数据类型存储位置不同。
-
Java 基本数据类型存放位置
方法参数、局部变量存放在栈内存中的栈桢中的局部变量表
常量存放在常量池中 -
包装类型如Integer存放位置
常量池
堆内存
Integer 存储在常量池中时可以使用对比,但当在堆内存中时,使用对比,实际对比的是两个内存地址而非值。
Reduce the number of conditional operators (4) used in the expression (maximum allowed 3)
在一个表达式中条件判断不应该超过三个
//修改前
boolean rollback = (receiveType == Constants.ONE || receiveType == Constants.TWO || receiveType == Constants.THREE) && (result == null || !result.isSuccess());
//修改后,提取成一个方法
boolean rollback = checkReceiveType(receiveType) && (result == null || !result.isSuccess());
private boolean checkReceiveType(int receiveType) {
return receiveType == Constants.ONE || receiveType == Constants.TWO || receiveType == Constants.THREE;
}
The Cyclomatic Complexity of this method "xxx" is 19 which is greater than 15 authorized.
代码的复杂度太高了,通常可以把代码中独立的业务逻辑抽取成单独的方法;
sonar扫描是按照一个条件判断算一个复杂度的,也就是说在一个方法中不要写超过15个条件判断;
灵活使用StringUtils.isAnyBlank/isNoneBlank/BooleanUtils.and/BooleanUtils.or可以把多个条件判断变成一个
//修改前
if(this.acId== null||this.userId==null||!Md5Util.encrypt(inputSign).equals(this.getMd5Sign())){
flag = false;
}
//修改后
if(StringUtils.isAnyBlank(this.acId,this.userId)||!Md5Util.encrypt(inputSign).equals(this.getMd5Sign())){
flag = false;
}
Return an empty collection instead of null
不能直接返回null
//修改前
return null
//修改后
return Collections.emptyList()/Collections.EmptyMap/Collections.EmptySet/new String[0]
Refactor this code to not nest more than 5 if/for/while/switch/try statements.
if/for/while/switch/try嵌套不能超过5层
Iterate over the "entrySet" instead of the "keySet"
遍历map时,使用entrySet,而不是keySet;
解释
"entrySet()" should be iterated when both the key and value are needed;
通过查看源代码发现,调用方法keySetMap.keySet()会生成KeyIterator迭代器,其next方法只返回其key值,而调用entrySetMap.entrySet()方法会生成EntryIterator 迭代器,其next方法返回一个Entry对象的一个实例,其中包含key和value。
所以当我们用到key和value时,用entrySet迭代性能更高
Use "Integer.parseInt" for this string-to-int conversion
使用Integer.parseInt 代替 Integer.valueOf
解释
Integer.parseInt(s)是把字符串解析成int基本类型,
Integer.valueOf(s)是把字符串解析成Integer对象类型
Replace "Collections.EMPTY_LIST" by "Collections.emptyList()
Collections.EMPTY_LIST VS Collections.emptyList()
Collections. emptyList()返回的也是一个空的List,它与Collections.EMPTY_LIST的唯一区别是,Collections. emptyList()支持泛型,所以在需要泛型的时候,可以使用Collections. emptyList()。
注意,这个空的集合是不能调用add来添加元素的,会直接抛异常
为啥不直接new ArrayList()呢?
因为new ArrayList()在初始化时会占用一定的资源
————————————————
参考:
https://blog.csdn.net/asdasd3418/article/details/83791630/
https://www.jianshu.com/p/f67a6f18e066