1. 程式人生 > >FindBugs What Why How

FindBugs What Why How



什麼是靜態程式碼分析

靜態程式碼分析是指無需執行被測程式碼,僅通過分析或檢查源程式的語法、結構、過程、介面等來檢查程式的正確性,找出程式碼隱藏的錯誤和缺陷,如引數不匹配,有歧義的巢狀語句,錯誤的遞迴,非法計算,可能出現的空指標引用等等。

在軟體開發過程中,靜態程式碼分析往往先於動態測試之前進行,同時也可以作為制定動態測試用例的參考。統計證明,在整個軟體開發生命週期中,30% 至 70% 的程式碼邏輯設計和編碼缺陷是可以通過靜態程式碼分析來發現和修復的。

靜態程式碼分析工具的優勢

1. 幫助程式開發人員自動執行靜態程式碼分析,快速定位程式碼隱藏錯誤和缺陷。

2. 幫助程式碼設計人員更專注於分析和解決程式碼設計缺陷。

3. 顯著減少在程式碼逐行檢查上花費的時間,提高軟體可靠性並節省軟體開發和測試成本。

靜態程式碼分析工具的分類

PMD CheckStyle 是基於.java 檔案,會生成抽象語法樹 AST,檢測的規則基於語法塊和表示式 。側重點是編碼風格,未使用的程式碼,重複程式碼等等層面的檢測

FindBugs 是基於class檔案或者jar包。在位元組碼層面,通過內建的一套規則進行缺陷模型的匹配,由於模型並不一定完全匹配,會有誤報漏報的產生, 另外由於是在位元組碼層面,單純的從程式碼角度看,有的錯誤會讓人覺得困惑。

FindBugs 和 Sonar

findbugs是sonar的子集,在sonar平臺中可以直接匯入findbugs的規則集。sonar比findbugs高了一個層級,多出了sonar不僅關注了常規靜態bug,還關注到了如程式碼質量、包與包,類與類之間的依賴情況、程式碼耦合情況、類,方法。檔案的複雜度、程式碼中是否包含大量複製貼上的程式碼是質量低下的,關注到了專案程式碼整體的健康情況。不過個人在使用過程中findbugs本身的規則比sonar的官方規則更加實用,high級別的bug都是較為實用的bug,且能覆蓋到一些效能方面的問題,sonar的規則,50%bug都是主要級別,其實危害不大。

安裝和使用

Findbugs的缺陷

Call to equals() comparing different types

equals接受的引數是object,傳入其他型別並不會報錯。所以需要確認到底本意如此還是程式碼中的bug

equals的實現

修改方法:

下面和上面的錯誤是類似的,但是有一點好,常量前置,避免了變數為null,引起空指標錯誤

 No relationship between generic parameter and method argument

呼叫contains的時候, 泛型引數和傳入的方法引數不匹配

This call to a generic collection method contains an argument with an incompatible class from that of the collection's parameter (i.e., the type of the argument is neither a supertype nor a subtype of the corresponding generic type argument). Therefore, it is unlikely that the collection contains any objects that are equal to the method argument used here. Most likely, the wrong value is being passed to the method.
In general, instances of two unrelated classes are not equal. For example, if the Foo and Bar classes are not related by subtyping, then an instance of Foo should not be equal to an instance of Bar. Among other issues, doing so will likely result in an equals method that is not symmetrical. For example, if you define the Foo class so that a Foo can be equal to a String, your equals method isn't symmetrical since a String can only be equal to a String.

一般來講,兩個不同的class是不會相等的,除非你自己實現了特定的equals方法,但是String只能和String相等

contains方法在arrayList中的實現

Suspicious reference comparison

兩個物件直接用==比較,比較的是堆空間上的記憶體地址

另外:自動拆箱只存在與一個是物件,一個是基本型別

Impossible cast

不可能成功的轉型

This cast will always throw a ClassCastException. FindBugs tracks type information from instanceof checks, and also uses more precise information about the types of values returned from methods and loaded from fields. Thus, it may have more precise information that just the declared type of a variable, and can use this to determine that a cast will always throw an exception at runtime.

equals method overrides equals in superclass and may not be symmetric

 重寫父類的equals方法,可能導致a 等於b,但是b不等於a的現象出現

This class defines an equals method that overrides an equals method in a superclass. Both equals methods methods use instanceof in the determination of whether two objects are equal. This is fraught with peril, since it is important that the equals method is symmetrical (in other words, a.equals(b) == b.equals(a)). If B is a subtype of A, and A's equals method checks that the argument is an instanceof A, and B's equals method checks that the argument is an instanceof B, it is quite likely that the equivalence relation defined by these methods is not symmetric.

Null value is guaranteed to be dereferenced:

需要進行非空的判斷,(只要對於物件是否是空進行了判斷就預設處理了null的情況)

修改方法

Method call passes null for non-null parameter

對於不接受null值的方法,傳入的引數要進行空判斷。

分析:

修改方法:

Possible null pointer dereference

有可能是誤報

An apparent infinite recursive loop

企圖呼叫不定引數引發的迴圈呼叫

測試樣例

More arguments are passed than are actually used in the format string

字串格式化中的佔位符數量與期望值不符

修改方法,使用Java提供的格式化方式

效能問題:

Boxing/unboxing to parse a primitive

setCardID接受一個基本型別 , this.cardKey是String型別

valueOf的實現 

修改方式,能傳基本型別,就用parseXXX這樣方法

Method concatenates strings using + in a loop

在迴圈中用+拼接字串

Why :

java,或者更具體的說,編譯器 針對+做了操作符過載,對於字串拼接的+,會生成StringBuilder

如果是迴圈,就會迴圈建立StringBuilder物件

總結

Findbugs 分析程式碼的能力是有限的,它主要目的作用是定位問題,之後更多的是需要人為的介入分析程式碼。工具的最終的目的是為了增強程式碼的健壯性,所以也不要一味追求解決所有的掃描結果