摘要:幫助公司部署了一套sonar平臺,通過一段時間運行,發現有一些問題出現頻率很高,所以有必要將這些問題進行整理總結和分析,避免再次出現相似問題。html
做者原創技術文章,轉載請註明出處java
===================================================================程序員
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:CRITICALapp
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.less
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
其餘推薦相關閱讀:
單元測試系列之四:Sonar平臺中項目主要指標以及代碼壞味道詳解
單元測試系列之七:Sonar 數據庫表關係整理一(rule相關)