Sonar 常用代码规则(二)
摘要:帮助公司部署了一套sonar平台,经过一段时间运行,发现有一些问题出现频率很高,因此有必要将这些问题进行整理总结和分析,避免再次出现类似问题。
作者原创技术文章,转载请注明出处
===================================================================
id: 85 name:Broken Null Check type:CODE SMELL severity:CRITICAL
Comment:The null check is broken since it will throw a Nullpointer itself. The reason is that a method is called on the object when it is null. It is likely that you used || instead of && or vice versa. <p> This rule is deprecated, use {rule:squid:S1697} instead. </p> definition:null检查是坏的,因为它将抛出一个Nullpointer本身。 原因是当对象为空时调用该方法。 很可能你使用|| 而不是&&,反之亦然。
advice: 不合规案例: if (str == null && str.length() == 0) { System.out.println("String is empty"); } if (str != null || str.length() > 0) { System.out.println("String is not empty"); } 合规案例: if (str == null || str.length() == 0) { System.out.println("String is empty"); } if (str != null && str.length() > 0) { System.out.println("String is not empty"); }
-------------------------------------------------------------------
id:123 name:Useless Operation On Immutable type:CODE SMELL severity:CRITICAL
Comment:An operation on an Immutable object (BigDecimal or BigInteger) won't change the object itself. The result of the operation is a new object. Therefore, ignoring the operation result is an error.
definition:示例代码: import java.math.*; class Test { void method1() { BigDecimal bd=new BigDecimal(10); bd.add(new BigDecimal(5)); // 这里违背了规则 } void method2() { BigDecimal bd=new BigDecimal(10); bd = bd.add(new BigDecimal(5)); // 这里没有违背规则 } }
advice: 对不可变对象(BigDecimal或BigInteger)的操作不会更改对象本身。 操作的结果是一个新的对象。 因此忽略操作结果是一个错误。
-------------------------------------------------------------------
id: 169 name:Empty Finally Block type:CODE SMELL severity:CRITICAL
Comment:<p> Avoid empty finally blocks - these can be deleted. </p> <p> This rule is deprecated, use {rule:squid:S00108} instead. </p>
definition:这些是可以删掉的。不合规案例: for (int i = 0; i < 42; i++){} // Empty on purpose or missing piece of code ?
advice: 空的 finally 块:避免空的 finally 块
-------------------------------------------------------------------
id: 263 name: type: severity: Comment:
definition:使用equals()比较对象引用; 避免用==,或者 != 进行比较。
advice:
不合规案例:
String str1 = "blue";
String str2 = "blue";
String str3 = str1;
if (str1 == str2)
{
System.out.println("they're both 'blue'"); // this doesn't print because the objects are different
}
if (str1 == "blue")
{
System.out.println("they're both 'blue'"); // this doesn't print because the objects are different
}
if (str1 == str3)
{
System.out.println("they're the same object"); // this prints
}
合规案例:
String str1 = "blue";
String str2 = "blue";
String str3 = str1;
if (str1.equals(str2))
{
System.out.println("they're both 'blue'"); // this prints
}
if (str1.equals("blue"))
{
System.out.println("they're both 'blue'"); // this prints
}
if (str1 == str3)
{
System.out.println("they're the same object"); // this still prints, but it's probably not what you meant to do
}
-------------------------------------------------------------------
id: 264 name: type: severity: Comment:
definition:空的 Synchronized 块:避免空的 synchronized 块 - 它们是无用的
advice: 不合规案例:
for (int i = 0; i < 42; i++){} // Empty on purpose or missing piece of code ?
-------------------------------------------------------------------
id:272 name: type: severity: Comment:
definition: 没有经验的程序员有时会混淆比较概念,并使用equals()来比较null值
advice:
不合规案例:
interface KitchenTool { ... };
interface Plant {...}
public class Spatula implements KitchenTool { ... }
public class Tree implements Plant { ...}
//...
Spatula spatula = new Spatula();
KitchenTool tool = spatula;
KitchenTool [] tools = {tool};
Tree tree = new Tree();
Plant plant = tree;
Tree [] trees = {tree};
if (spatula.equals(tree)) { // Noncompliant; unrelated classes
// ...
}
else if (spatula.equals(plant)) { // Noncompliant; unrelated class and interface
// ...
}
else if (tool.equals(plant)) { // Noncompliant; unrelated interfaces
// ...
}
else if (tool.equals(tools)) { // Noncompliant; array & non-array
// ...
}
else if (trees.equals(tools)) { // Noncompliant; incompatible arrays
// ...
}
else if (tree.equals(null)) { // Noncompliant
// ...
}
-------------------------------------------------------------------
id: 796 name: type: severity: Comment:
definition:此方法调用notify()而不是notifyAll()
advice: Java监视器通常用于多个条件。 调用notify()只唤醒一个线程,这意味着线程唤醒可能不是等待调用者满足的条件的线程。
-------------------------------------------------------------------
id:800 name: type: severity: Comment:
definition:此构造函数读取尚未分配值的字段。 这通常是由程序员错误地使用该字段而不是构造函数的参数之一引起的。
advice:
此构造方法中使用了一个尚未赋值的字段或属性。
String a;
public SA() {
String abc = a;
System.out.println(abc);
}
-------------------------------------------------------------------
id: 802 name: type: severity: Comment:
definition: 格式字符串定义错误
advice: 例如:formatter.format("%<s %s", "a", "b"); 抛出MissingFormatArgumentException异常
-------------------------------------------------------------------
id:806 name: type: severity: Comment:
definition:此代码创建一个异常(或错误)的对象,但不会用它做任何事情
advice:
例如:if (x < 0)
new IllegalArgumentException("x must be nonnegative");
这可能是程序员的意图抛出创建的异常:
if (x < 0)
throw new IllegalArgumentException("x must be nonnegative");
-------------------------------------------------------------------
id:811 name: type: severity: Comment:
definition:有一个语句或分支,如果执行保证在此时值为空,并且该值保证被取消引用(除了涉及运行时异常的转发路径之外)。
advice: 在正常的null判断分支上,对象去除引用操作是受保护的不允许的
-------------------------------------------------------------------
id: 815 name: type: severity: Comment:
definition:"equals(Object o)"方法不能对参数o的类型做任何的假设。比较此对象与指定的对象。当且仅当该参数不为 null,并且是表示与此对象相同的类型的对象时,结果才为 true
advice:
示例代码:
public class Foo {
// some code
public void equals(Object o) {
Foo other = (Foo) o;
// the real equals code
}
}
原因:
当你在实现类的equals方法时,不应该对参数有任何的预先设定。如上代码所写,
则设定了参数o肯定是Foo类的一个对象.但是如果在函数调用时,参数o不是一个Foo类或其子类,
就会导致代码会抛出一个ClassCastException。因此在实现equals方法,应该加一个判断,如果参数o不是一个Foo类对象,则返回false。
-------------------------------------------------------------------
id: 824 name: type: severity: Comment:
definition:该代码同步一个封装的原始常量,例如一个Boolean类型。
advice:
private static Boolean inited = Boolean.FALSE;
...
synchronized(inited) {
if (!inited) {
init();
inited = Boolean.TRUE;
}
}
...
由于通常只存在两个布尔对象,此代码可能是同步的其他无关的代码中相同的对象,这时会导致反应迟钝和可能死锁
-------------------------------------------------------------------
id: 827 name: type: severity: Comment:
definition: 可以为null的值存储在已注释为@Nonnull的字段中。
advice: 为一个已经声明为不能为null值的属性赋值为null
-------------------------------------------------------------------
id:831 name: type: severity: Comment:
definition: 调用具有可变数量参数的格式字符串方法,但传递的参数数与格式字符串中%占位符的数量不匹配。 这可能不是作者的意图。
advice: 错误用法 - 格式化字符串参数的数目与占位符不相等
-------------------------------------------------------------------
id: 844 name: type: severity: Comment:
definition:
某些异常控制路径上的引用值为空,在此处将被解引用。 当执行代码时,这可能会导致NullPointerException异常。 请注意,因为FindBugs目前不修剪不可行的异常路径,这可能是一个错误的警告。
另请注意,FindBugs将switch语句的默认情况视为异常路径,因为默认情况通常是不可行的。
advice: 在异常null值处理分支调用的方法上,可能存在对象去除引用操作
-------------------------------------------------------------------
id:846 name: type: severity: Comment:
definition: 没有足够的参数传递以满足格式字符串中的占位符。 执行此语句时将发生运行时异常。
advice: String的format操作缺少必要的参数。
-------------------------------------------------------------------
id: 849 name: type: severity: Comment:
definition:该代码将保证为非负的值与负常数或零进行比较。
advice: 保证非负数和负数进行比较
-------------------------------------------------------------------
id: 855 name: type: severity: Comment:
definition: hasNext()方法调用next()方法。
advice: 这几乎肯定是错误的,因为hasNext()方法不应该改变迭代器的状态,而下一个方法应该改变迭代器的状态。
-------------------------------------------------------------------
id:856 name: type: severity: Comment:
definition: 该方法似乎在循环中使用连接构建一个String。 在每次迭代中,String将转换为StringBuffer / StringBuilder,附加到并转换为String。 这可以导致迭代次数中的二次成本,因为每个迭代中重新生成增长的字符串。
advice:
通过使用StringBuffer(或Java 1.5中的StringBuilder)可以获得更好的性能。
例如:
// 不好的写法
String s = "";
for (int i = 0; i < field.length; ++i) {
s = s + field[i];
}
//优化的写法
StringBuffer buf = new StringBuffer();
for (int i = 0; i < field.length; ++i) {
buf.append(field[i]);
}
String s = buf.toString();
-------------------------------------------------------------------
id:857 name: type: severity: Comment:
definition:
格式字符串占位符与相应的参数不兼容。 例如System.out.println(“%d \ n”,“hello”);
%d占位符需要一个数字参数,但是却传递一个字符串值。 执行此语句时将发生运行时异常。
advice:
错误使用参数类型来格式化字符串
-------------------------------------------------------------------
id:873 name: type: severity: Comment:
definition:
代码在interned String上同步。
private static String LOCK =“LOCK”;
...
synchronized(LOCK){...}
...
advice:
常量字符串被实体化并由JVM加载的所有其他类共享。 因此,这可能锁定什么对象导致其他代码也可能被锁。 这可能导致阻塞和死锁行为。
-------------------------------------------------------------------
id: 878 name: type: severity: Comment: definition: 按位添加有符号字节值。添加一个字节值和已知具有8个较低位清除的值。 在对值进行任何按位操作之前,从字节数组加载的值将被扩展为32位。 因此,如果b [0]包含值0xff,并且x最初为0,则代码((x << 8)+ b [0])将对扩展0xff进行符号扩展,以获得0xffffffff,从而给出值0xffffffff作为 结果。
advice:
将字节数组打包到int中的以下代码是非常错误的:
int result = 0;
for(int i = 0; i < 4; i++)
result = ((result << 8) + b[i]);
需要改成如下:
int result = 0;
for(int i = 0; i < 4; i++)
result = ((result << 8) + (b[i] & 0xff));
-------------------------------------------------------------------
id:879 name: type: severity: Comment:
definition: 方法调用将null传递给非空参数。可能为null的值传递给非空方法参数。
advice: 参数注释为始终为非空值的参数,或者分析表明它始终被取消引用。
-------------------------------------------------------------------
id: 880 name: type: severity: Comment:
definition:此构造函数读取尚未分配值的字段。 这通常是由程序员错误地使用该字段而不是构造函数的参数之一引起的。
advice:
此构造方法中使用了一个尚未赋值的字段或属性。例如:
String a;
public SA() {
String abc = a;
System.out.println(abc);
}
===================================================================
看完点个赞呗,难道想白嫖不成?更多内容请访问微信公众号 :三国测,扫码关注哟!
感谢阅读,作者原创技术文章,转载请注明出处
附录:参考文献&参考文章
Java代码规范小结(一):http://www.jianshu.com/p/b50f01eeba4d
FindBugs Report安全代码检查工具问题解析:http://blog.csdn.net/wwbmyos/article/details/50549650
FindBugs规则整理(转载):http://blog.csdn.net/hufang_lele/article/details/47090215
详解FindBugs的各项检测器:http://blog.csdn.net/yang1982_0907/article/details/18606171
其他推荐相关阅读:
单元测试系列之一:如何使用JUnit、JaCoCo和EclEmma提高单元测试覆盖率
单元测试系列之四:Sonar平台中项目主要指标以及代码坏味道详解
单元测试系列之七:Sonar 数据库表关系整理一(rule相关)