Findbugs安裝使用說明
Findbugs安裝使用說明
1用途
1. FindBugs 是一個java bytecode靜態分析工具,它可以幫助java工程師提高代碼質量以及排除隱含的缺陷。
例如:未關閉的數據庫連接,缺少必要的null check,多余的 null check,多余的if后置條件,相同的條件分支,重復的代碼塊,錯誤的使用了"==",建議使用StringBuffer代替字符串連加等等。而且我們還可以自己配置檢查規則(做哪些檢查,不做哪些檢查),也可以自己來實現獨有的校驗規則(用戶自定義特定的bug模式需要繼承它的接口,編寫自己的校驗類,屬于高級技巧)。
2. FindBugs檢查類或者 JAR 文件,將字節碼與一組缺陷模式進行對比以發現可能的問題。Findbugs自帶檢測器,其中有60余種Bad practice,80余種Correctness,1種 Internationalization,12種Malicious code vulnerability,27種Multithreaded correctness,23種Performance,43種Dodgy。
2 安裝
1. 解壓縮 findbugs.zip到 eclipse下的dropins目錄
2、重啟eclipse,選中項目,右鍵會出現一個Find Bugs菜單。至此,findbugs插件安裝完畢。
然后在Package Explorer或Navigator視圖中,選中你的Java項目,點擊右鍵,可以看到“Find Bugs”菜單項,子菜單項里有“Find Bugs”和“Clear Bug Markers”兩項內容。
3 使用
啟動
選中java工程,點擊鼠標右鍵,選擇名為“Find Bugs”的菜單,點擊FindBugs,開始運行,問題指示器將指向根據bug模式識別出來的潛在問題代碼位置。
我們點中“Find Bugs”,運行結束后可以在Problems中看到增加了如下的警告信息內容。
也可以添加findbugs的視圖,里面有錯誤詳細分類
FindBugs運行后的警告信息內容不僅在Problems視圖中顯示,而且將標記在源代碼標記框中,在源代碼編輯器中我們可以看到警告標識, 當光標指向你的警告信息的代碼上面時,就會有相應的錯誤提示信息,與Eclipse本身的錯誤或警告信息提示類似。
選中Problems視圖里出現的相應問題,就會在代碼編輯器里切換到相應的代碼上去,方便根據相應的提示信息進行代碼的修改。
在Problems視圖里,選中相應的問題條目,右鍵,在彈出的菜單中,可以看到“Show Bug info”。
點中它,會切換到Bug Details視圖上去,顯示更加詳細的提示信息。當然,在代碼編輯窗口中,點擊帶有警告提示信息的圖標時,也會自動切換到Bug Details窗口去,查看詳細的警告信息。
可選項定制
你還可以通過java工程的屬性對話框來定制findbugs的運行方式,選擇你的項目,右鍵點擊 Properties,可選項包括:
a. 控制"Run FindBugs Automatically" 開關的checkbox。 選中時, FindBugs 將在每次修改java類后啟動運行。
b.選擇最小告警優先級和Bug類別。這些選項將選擇哪些警告被顯示。例如,如果你選擇"Medium",只有Medium 和 High priority 警告將被顯示。近似地,如果你未選中 "Style" checkbox,Style類的警告信息將不會被顯示。
c.選擇探測器。這個列表允許你選擇你想在工程中使用的探測器。
4 配套的Bug模式解釋
為了有針對性的使用這個工具,減少bug的誤報,提高使用效率,我們選擇了10個左右的bug模式,下面就是對這10個模式的解釋。
這些bug可能會引起程序的性能或邏輯問題.
需要說明的是,findbugs能檢測的bug pattern遠不僅于此,甚至可以定制自己的探測器,因此,這個文檔會不斷擴充,同時,也歡迎大家不斷探索和分享使用實踐.
4.1 ES_COMPARING_PARAMETER_STRING_WITH_EQ
ES: Comparison of String parameter using == or != (ES_COMPARING_PARAMETER_STRING_WITH_EQ)
This code compares a java.lang.String parameter for reference equality using the == or != operators. Requiring callers to pass only String constants or interned strings to a method is unnecessarily fragile, and rarely leads to measurable performance gains. Consider using the equals(Object) method instead.
使用 == 或者 != 來比較字符串或interned字符串,不會獲得顯著的性能提升,同時并不可靠,請考慮使用equals()方法。
4.2 HE_EQUALS_NO_HASHCODE
HE: Class defines equals() but not hashCode() (HE_EQUALS_NO_HASHCODE)
This class overrides equals(Object), but does not override hashCode(). Therefore, the class may violate the invariant that equal objects must have equal hashcodes.
類定義了equals()方法但沒有重寫hashCode()方法,這樣違背了相同對象必須具有相同的hashcodes的原則
4.3 IT_NO_SUCH_ELEMENT
It: Iterator next() method can't throw NoSuchElement exception (IT_NO_SUCH_ELEMENT)
This class implements the java.util.Iterator interface. However, its next() method is not capable of throwing java.util.NoSuchElementException. The next() method should be changed so it throws NoSuchElementException if is called when there are no more elements to return.
迭代器Iterator無法拋出NoSuchElement異常,類實現了java.util.Iterator接口,但是next()方法無法拋出java.util.NoSuchElementException異常,因此,next()方法應該做如此修改,當被調用時,如果沒有element返回,則拋出NoSuchElementException異常
4.4 J2EE_STORE_OF_NON_SERIALIZABLE_OBJECT_INTO_SESSION
J2EE: Store of non serializable object into HttpSession (J2EE_STORE_OF_NON_SERIALIZABLE_OBJECT_INTO_SESSION)
This code seems to be storing a non-serializable object into an HttpSession. If this session is passivated or migrated, an error will result.
將沒有實現serializable的對象放到HttpSession中,當這個session被鈍化和遷移時,將會產生錯誤,建議放到HttpSession中的對象都實現serializable接口。
4.5 ODR_OPEN_DATABASE_RESOURCE
ODR: Method may fail to close database resource (ODR_OPEN_DATABASE_RESOURCE)
The method creates a database resource (such as a database connection or row set), does not assign it to any fields, pass it to other methods, or return it, and does not appear to close the object on all paths out of the method. Failure to close database resources on all paths out of a method may result in poor performance, and could cause the application to have problems communicating with the database.
方法可能未關閉數據庫資源,未關閉數據庫資源將會導致性能變差,還可能引起應用與服務器間的通訊問題。
4.6 OS_OPEN_STREAM
OS: Method may fail to close stream (OS_OPEN_STREAM)
The method creates an IO stream object, does not assign it to any fields, pass it to other methods that might close it, or return it, and does not appear to close the stream on all paths out of the method. This may result in a file descriptor leak. It is generally a good idea to use a finally block to ensure that streams are closed.
方法可能未關閉stream,方法產生了一個IO流,卻未關閉,將會導致文件描繪符的泄漏,建議使用finally block來確保io stream被關閉。
4.7 DMI_CALLING_NEXT_FROM_HASNEXT
DMI: hasNext method invokes next (DMI_CALLING_NEXT_FROM_HASNEXT)
The hasNext() method invokes the next() method. This is almost certainly wrong, since the hasNext() method is not supposed to change the state of the iterator, and the next method is supposed to change the state of the iterator.
4.8 IL_INFINITE_LOOP
IL: An apparent infinite loop (IL_INFINITE_LOOP)
This loop doesn't seem to have a way to terminate (other than by perhaps throwing an exception).
明顯的無限循環.
4.9 IL_INFINITE_RECURSIVE_LOOP
IL: An apparent infinite recursive loop (IL_INFINITE_RECURSIVE_LOOP)
This method unconditionally invokes itself. This would seem to indicate an infinite recursive loop that will result in a stack overflow.
明顯的無限迭代循環,將導致堆棧溢出.
4.10 WMI_WRONG_MAP_ITERATOR
WMI: Inefficient use of keySet iterator instead of entrySet iterator (WMI_WRONG_MAP_ITERATOR)
This method accesses the value of a Map entry, using a key that was retrieved from a keySet iterator. It is more efficient to use an iterator on the entrySet of the map, to avoid the Map.get(key) lookup.
使用了keySet iterator和Map.get(key)來獲取Map值,這種方式效率低,建議使用entrySet的iterator效率更高.
4.11 IM_BAD_CHECK_FOR_ODD
IM: Check for oddness that won't work for negative numbers (IM_BAD_CHECK_FOR_ODD)
The code uses x % 2 == 1 to check to see if a value is odd, but this won't work for negative numbers (e.g., (-5) % 2 == -1). If this code is intending to check for oddness, consider using x & 1 == 1, or x % 2 != 0.
奇偶檢測邏輯,未考慮負數情況.
5 eclipse自帶告警工具
在包管理器界面
帶有感嘆號的包和類 就是含有告警
在問題視圖也可以看到所有的告警
雙擊就能看到具體錯誤的地方,使用和findbugs類似
6安卓自帶告警工具
點擊運行后會自動彈出
雙擊就能看到具體錯誤的地方,使用和findbugs類似
7附錄
Bad practice 壞的實踐
一些不好的實踐,下面列舉幾個:
HE : 類定義了equals() ,卻沒有hashCode() ;或類定義了equals() ,卻使用Object.hashCode() ;或類定義了hashCode() ,卻沒有equals() ;或類定義了hashCode() ,卻使用Object.equals() ;類繼承了equals() ,卻使用Object.hashCode() 。
SQL : Statement 的execute 方法調用了非常量的字符串;或Prepared Statement 是由一個非常量的字符串產生。
DE : 方法終止或不處理異常,一般情況下,異常應該被處理或報告,或被方法拋出。
Correctness 一般的正確性問題
可能導致錯誤的代碼,下面列舉幾個:
NP : 空指針被引用;在方法的異常路徑里,空指針被引用;方法沒有檢查參數是否null ;null 值產生并被引用;null 值產生并在方法的異常路徑被引用;傳給方法一個聲明為@NonNull 的null 參數;方法的返回值聲明為@NonNull 實際是null 。
Nm : 類定義了hashcode() 方法,但實際上并未覆蓋父類Object 的hashCode() ;類定義了tostring() 方法,但實際上并未覆蓋父類Object 的toString() ;很明顯的方法和構造器混淆;方法名容易混淆。
SQL : 方法嘗試訪問一個Prepared Statement 的0 索引;方法嘗試訪問一個ResultSet 的0 索引。
UwF : 所有的write 都把屬性置成null ,這樣所有的讀取都是null ,這樣這個屬性是否有必要存在;或屬性從沒有被write 。
Internationalization 國際化
當對字符串使用upper 或lowercase 方法,如果是國際的字符串,可能會不恰當的轉換。
Malicious code vulnerability 可能受到的惡意攻擊
如果代碼公開,可能受到惡意攻擊的代碼,下面列舉幾個:
FI : 一個類的finalize() 應該是protected ,而不是public 的。
MS : 屬性是可變的數組;屬性是可變的Hashtable ;屬性應該是package protected 的。
Multithreaded correctness 多線程的正確性
多線程編程時,可能導致錯誤的代碼,下面列舉幾個:
ESync : 空的同步塊,很難被正確使用。
MWN : 錯誤使用notify() ,可能導致IllegalMonitorStateException 異常;或錯誤的
使用wait() 。
No : 使用notify() 而不是notifyAll() ,只是喚醒一個線程而不是所有等待的線程。
SC : 構造器調用了Thread.start() ,當該類被繼承可能會導致錯誤。
Performance 性能問題
可能導致性能不佳的代碼,下面列舉幾個:
DM : 方法調用了低效的Boolean 的構造器,而應該用Boolean.valueOf( …) ;用類似
Integer.toString(1) 代替new Integer(1).toString() ;方法調用了低效的float 的構造器,應該用靜態的valueOf 方法。
SIC : 如果一個內部類想在更廣泛的地方被引用,它應該聲明為static 。
SS : 如果一個實例屬性不被讀取,考慮聲明為static 。
UrF : 如果一個屬性從沒有被read ,考慮從類中去掉。
UuF : 如果一個屬性從沒有被使用,考慮從類中去掉。
Dodgy 危險的
具有潛在危險的代碼,可能運行期產生錯誤,下面列舉幾個:
CI : 類聲明為final 但聲明了protected 的屬性。
DLS : 對一個本地變量賦值,但卻沒有讀取該本地變量;本地變量賦值成null ,卻沒有讀取該本地變量。
ICAST : 整型數字相乘結果轉化為長整型數字,應該將整型先轉化為長整型數字再相乘。
INT : 沒必要的整型數字比較,如X <= Integer.MAX_VALUE 。
NP : 對readline() 的直接引用,而沒有判斷是否null ;對方法調用的直接引用,而方法可能返回null 。
REC : 直接捕獲Exception ,而實際上可能是RuntimeException 。
ST: 從實例方法里直接修改類變量,即static屬性。