轉自:http://blog.csdn.net/jizi7618937/article/details/51500725
Avoid Array Loops
數組之間的拷貝使用System.arrayCopy更加高效
byte[] ReceiveBytes = new byte[length1+ length2];
for (int i = 0; i < length1; i++) {
ReceiveBytes[i] =ReceiveBytes_temp1[i];
}
Big Integer Instantiation
避免創建已經存在的Big Integer對象 ,如:(BigDecimal.ZERO,BigDecimal.ONE, BigDecimal.TEN)
Boolean Instantiation
避免創建已經存在的Boolean 對象;如:Boolean.TRUE, Boolean.FALSE
Final field Could Be Static
有Final修飾符的成員變量必須是靜態的
Explicitly invokes garbage collection
避免顯示調用垃圾回收
Inefficient use of keySet iterator instead of entrySetiterator
低效利用使用keySet迭代器而不是entrySet迭代器。
使用entrySet效率會比keySet高
for (String key : map.keySet()) {
//to do some thing
}
for (Entry entry : map.entrySet()) {
//to do some thing
}
Method Concatenates String Using + In Loop
避免在循環中使用“+” 連接字符串。使用Stringbuffer 或Stringbuilder
private method is never called
定義為Private類型方法從未被調用,應該被刪除
Use ArrayList Instead Of Vector
使用ArrayList 替換Vector
Use Arrays As List
如果從數組轉換成一個List,用Arrays. AsList() 替換遍歷數組的形式轉換
UnnecessarilyLocal Before Return
避免創建無用的局部變量,如:
String s = getxx();
return s;
直接替換為return getxx();
Use IndexOf Char
當參數是單個字符的時候使用 String.indexOf(char)替換String.indexOf(String)
比如:用s.indexOf(‘a‘) 代替s.indexOf(“a”)
Method Invokes inefficient new String() constructor
如:String s = new String();
正確寫法 String s = “”;
Method Invokes inefficient new String(string) constructor
如:String s = new String(“test”);
正確寫法 String s = “test”;
Method Invokes inefficient Number constructor
Long, Integer, Short, Character, and Byte 使用valueOf代替直接實例化
Number 類型從-128 到127會緩存到常量池,可以節省內存
Integer i = new Integer(4);
Integer j = new Integer(4);
System.out.println(i==j);// false
i = Integer.valueOf(4);
j = Integer.valueOf(4);
System.out.println(i==j); // true
i = Integer.valueOf(128);
j = Integer.valueOf(128);
System.out.println(i==j);//false
Primitive value is boxed then unboxed to perform primitivecoercion
對原始值進行裝箱然后立即把它強制轉換為另外一種原始類型。例如:
new Double(d).intValue()應該直接進行強制轉換例如:(int)d
Class defines equals() but not hashCode()
Unused import
無用的包導入
Unused local variable
無用的局部變量
Unused formal parameter
未用的常規參數:避免傳遞給方法或構造器不使用的參數
TODO Comment
代碼中包含TODO注釋
Empty Statement
避免使用空代碼塊
Don't Import Java.Lang
Collapsible If Statements
有時候兩個 if 語句可以通過布爾短路操作符分隔條件表達式組合成一條語句
如:
If(a==b){
If(c==1){
//do some thing
}
}
Avoid Decimal Literals In BigDecimal Constructor
避免在 BigDecimal 類型的構造方法中用小數類型的字面量:人們常常以
為”new BigDecimal(0.1)”能精確等於 0.1, 其實不然,它等於“ 0. 1000000000000000055511151231257827021181583404541015625 ”,這 種狀況的原因是 0.1 不能精確的表示雙精度類型,因此,傳入構造器的 long 類型不等於 0.1 ,而傳入 String 類型的構造器 new BigDecimal(“0.1”) 可以精確等於 0.1, 故推薦這種情形時用 String 類型的構造器
Broken Null Check
破壞空檢查:如果自身拋出空指針異常空檢查就會遭到破壞,比如你使用 || 代替 && ,反之亦然。
if (string!=null ||!string.equals("")) { // 這里應該是&&
return string;
}
Close Resource
關閉資源:確保這些資源(譬如:Connection,Statement,和 ResultSet 對象)總在使用后被關閉
Compare Objects With Equals
對象相等性比較:使用 equals()比較對象的引用,避免使用”==”來比較
"." used for regular expression
String的split,replaceAll等方法傳遞的參數是正則表達式,正則表達式本身用到的字符需要轉義,如:句點符號“.”,美元符號“$”,乘方符號“^”,大括號“{}”,方括號“[]”,圓括號“()”,豎線“|”,星號“*”,加號“+”,問號“?”等等,這些需要在前面加上“\\”轉義符。
如:s = s.replaceAll(".", "/"); 應該使用s =s.replaceAll("\\.", "/");
An apparent infinite loop
明顯的無限循環
An apparent infinite recursive loop
明顯的無限迭代循環,將導致堆棧溢出
Equals And HashCode
重寫equals 后必須重寫hashCode
Equals Null
避免equals()方法和 null 比較
Junit TestShould Include Assert
單元測試必須包含斷言,而不是簡單的打印結果后看輸出。
Useless Operation On Immutable
對於不變類型的無用操作:對於不變類型對象 (String,BigDecimal 或BigInteger) 的操作不會改變對象本身,但操作結果是產生新的對象,所以操作的結果是錯的
如:BigDecimal a=new BigDecimal(10);
a.add(newBigDecimal(5));
正確的寫法:
BigDecimal bd=new BigDecimal(10);
bd = bd.add(new BigDecimal(5));
String Literals Equality
避免用== or != 比較 String
StringBuffer Instantiation With Char
StringBuffer sb = new StringBuffer('c');
字符 c 會轉換為 int 值,作為 StringBuffer 的初始化大小參數
Servlet reflected cross site scripting vulnerability
public void doGet(HttpServletRequestrequest,HttpServletResponse response)throws ServletException,IOException{
String v = request.getParameter("v");
PrintWriter out = response.getWriter();
out.print("協議版本號不對,v="+v);
out.close();
}
這里字符串v沒有作過濾,直接返回給用戶,有可能操作XSS攻擊
JSP reflected cross site scripting vulnerability
在代碼中在JSP輸出中直接寫入一個HTTP參數,這會造成一個跨站點的腳本漏洞
Call to static DateFormat
private static SimpleDateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");
避免使用靜態的DateFormat,DateFormat 是非線程安全的
Call to static Calendar
同上
Don’t use removeAll to clear a collection
清空集合使用clear() 代替removeAll()
Avoid printStackTrace
在代碼中避免使用e.printStackTrace,使用logger代替
System.println
代碼中禁止使用System.println
While For loop If Else Stmts Must use braces
While for 循環If Else 代碼塊必須使用大括號
Dead store to local variable
為局部變量賦值,但在其后的沒有對她做任何使用。通常,這表明一個錯誤,因為值從未使用過。
Method uses the same code for two branches
此方法使用相同的代碼,以實現兩個有條件的分支。檢查以確保這是不是一個編碼錯誤
checkstyle常見提示速查
Checkstyle常見錯誤和警告提示見下表所示:
| 錯誤提示
|
錯誤說明
|
| 缺少類注釋 |
|
| 行長度超過X個字符(包括空格) |
|
| 一個方法內的返回數量是X(最大值只能為3) |
|
| 最大的if-else嵌套層數為X(最大只能為3) |
|
| 數組的方括號“[]”的位置不正確(檢查數組類型的定義是String[] args,而不是String args[]) |
|
| 本行包含System.out.println語句 |
|
| 縮進不正確,一般是因為沒有在Eclipse中使用4個空格代替tab鍵引起。 |
|
| static修飾符沒有按照JLS的建議來排序(eg.寫成public final static...應該改成public static final) |
|
| 正則表達式)
|
名稱不符合正則表達式'^[A-Z][A-Z0-9][_A-Z0-9+]$'(即為大寫字母,數字、下划線等)。
一般在靜態變量沒有大寫時提示,包名不是全部消息時提示,類名不是大寫開頭時提示,方法名不是小寫開頭時提示 |
| 變量定義順序不正確(例如在類成員變量定義時,將private類型的變量定義在public類型的變量之前) |
|
| 靜態變量定義順序不正確(例如在構造函數之后定義靜態變量) |
|
| 成員變量定義順序不正確(例如在構造函數之后定義成員變量) |
|
| X是一個魔術數字(非0、1、2的數字) |
|
| if結構必須使用'{}' |
|
| 因為沒有設置checkstyle配置文件的charset為UTF-8,而類文件使用UTF-8編碼,並且含有中文 |
|
| “{” should be on the previous line
|
“{” 應該位於前一行
|
| 方法前面缺少javadoc注釋 |
|
| “Exception”
|
在注釋中希望有@throws的說明
|
| “.” Is preceeded with whitespace
|
“.” 前面不能有空格
|
| “.” Is followed by whitespace
|
“.” 后面不能有空格
|
| “=” is not preceeded with whitespace“=”
|
前面缺少空格
|
| “=” is not followed with whitespace
|
“=” 后面缺少空格
|
| “}” should be on the same line
|
“}” 應該與下條語句位於同一行
|
| “unused”
|
沒有參數“unused”,不需注釋
|
| “X” missing javadoc
|
變量“CA”缺少javadoc注釋
|
| 行含有”tab” 字符 |
|
| “Public” modifier
|
冗余的“public” modifier
|
| final修飾符的順序錯誤 |
|
| “.*” form of import
|
格式避免使用“.*”
|
| 從同一個包中Import內容 |
|
| Unused import-X Import |
的X類沒有被使用
|
| 重復Import同一個內容 |
|
| 從非法包中 Import內容 |
|
| “while” construct must use “{}”
|
“while” 語句缺少“{}”
|
| “X” must be private and have accessor method
|
變量“X”應該是private的,並且有調用它的方法
|
| “X” must match pattern “^[a-z][a-zA-Z0-9]*$”
|
變量“X”不符合命名規則“^[a-z][a-zA-Z0-9]*$”
|
| “(” is followed by whitespace
|
“(” 后面不能有空格
|
| “)” is proceeded by whitespace
|
“)” 前面不能有空格
|
PMD
檢查Java源文件中的潛在問題。
主要包括:
- 空try/catch/finally/switch語句塊
- 未使用的局部變量、參數和private方法
- 空if/while語句
- 過於復雜的表達式,如不必要的if語句等
- 復雜類
CheckStyle
檢查java源文件是否與代碼規范相符
主要包括
- Javadoc注釋
- 命名規范
- Headers
- Imports
- Size沖突和度量,如過長的方法
- Whitespace
- Modifiers
- Blocks
- Coding Problems
- Class Design
- 重復代碼
- Miscellaneous Checks
- Optional Checks
配套的Bug解釋模式
為了有針對性的使用這個工具,減少bug的誤報,提高使用效率,我們選擇了10個左右的bug模式,下面就是對這10個模式的解釋。
這些bug可能會引起程序的性能或邏輯問題.
需要說明的是,findbugs能檢測的bug pattern遠不僅於此,甚至可以定制自己的探測器,因此,這個文檔會不斷擴充,同時,也歡迎大家不斷探索和分享使用實踐.
大的分類主要包括以下幾種:
| Bad practice |
不好的習慣 |
| Correctness |
代碼的正確性 |
| Dodgy |
小問題 |
| Malicious code vulnerability |
惡意代碼 |
| Internationalization |
國際化問題 |
| Performance |
性能問題 |
| Security |
安全性問題 |
| Multithreaded currectness |
線程問題 |
| Experrimental |
實驗性問題 |
FindBugs常見錯誤描述和解決方法
(一)[DLS_DEAD_LOCAL_STORE]
描述: Dead store to 未使用的局部變量
解決方法:局部變量定義后未使用;實例化對象后又重新對該對象賦值
(二) [ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD]
描述:Write to static field 通過實例方法更新靜態屬性
常見於常量類,直接通過類名.常量名獲取的方式違背了封裝的原則,findbugs不提倡使用,而如果將常量改成靜態成員變量,又因為spring不支持靜態注入導致不能實現,解決方法是非靜態的setter調用靜態的setter方法給靜態成員變量賦值。
解決方法:
常量類F:
class F{
public static String a = “123”;
}
常量a改為靜態成員變量,通過F.getA()獲取,且由於spring不支持靜態注入,改為:
class F{
private static String a;
public static Integer getA() {
return a;
}
public void setA(String a) {
setAValue(a);
}
public static void setAValue(String a) {
F.a = a;
}
}
(三) [BX_UNBOXING_IMMEDIATELY_REBOXED]
描述: Boxed value is unboxed and then immediately reboxed 裝箱的值被拆箱,然后立刻重新裝箱了
常見的是三目運算時,同時存在基本類型和包裝類型。
解決方法:
Integer a = null;
//...
a = (a == null)?0:a;
此問題在於a不為null時,會被拆箱,賦值時再裝箱。這是自動裝箱拆箱的特性,只要運算中有不同類型,當涉及到類型轉換時,編譯器就會向下轉型,再進行運算。修改方法,統一類型:
Integer a = null;
//...
a = (a == null)?Integer.valueOf(0):a;
(四) [SE_BAD_FIELD]
描述: Non-transient non-serializable instance field in serializable class在可序列化的類中存在不能序列化或者不能暫存的數據
解決方法:
方法1:序列化該對象
方法2:當采用struts2框架開發,不可避免的此問題會大量出現,因為ActionSupport實現了序列化接口,action繼承了此類,而service沒序列化,所以在action中引用service對象時提示此錯誤,最簡單的解決方法是將service對象聲明成transient,即service不需要序列化
方法3(未驗證):To avoid Java serialization you need to implement writeObject() and readObject() method in your Class and need to throw NotSerializableException from those method.(action中實現這兩個方法?)
private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException {
throw new java.io.NotSerializableException( getClass().getName() );
}
private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException {
throw new java.io.NotSerializableException( getClass().getName() );
}
(五) [NP_LOAD_OF_KNOWN_NULL_VALUE]
描述: Load of known null value加載已知是null的值
解決方法:已知方法參數為null是,直接傳遞null而不是參數名
(六) [REC_CATCH_EXCEPTION]
描述: Exception is caught when Exception is not thrown 過泛地捕獲異常或捕獲異常后未做任何處理
解決方法:異常分類捕獲(至少要打印出此異常對象)
(七) [NP_NULL_PARAM_DEREF]
描述: Null passed for nonnull parameter 把空值傳給了非空的參數
解決方法:增加非空判斷
(八) [NP_IMMEDIATE_DEREFERENCE_OF_READLINE]
描述: Immediate dereference of the result of readLine() 立即引用了readLine()的結果
解決方法:判斷readLine的結果是否為空
(九) [EI_EXPOSE_REP] 惡意代碼漏洞
描述:may expose internal representation by returning getter方法返回引用類型
eclipse自動生成的引用類型(Object、數組、Date等)的getter、setter方法會得到或通過對可變對象的引用操作而暴露代碼內部實現,解決方法很多,只要返回的或賦值的對象不是原引用對象即可。
解決方法:
以Date類型為例:
public Date getHappenTime() {
if(happenTime != null){
return (Date) happenTime.clone();
}
return null;
}
(十) [ EI_EXPOSE_REP2] 惡意代碼漏洞
描述:may expose internal representation by storing an externally mutable object into setter方法返回引用類型
eclipse自動生成的引用類型(Object、數組、Date等)的getter、setter方法會得到或通過對可變對象的引用操作而暴露代碼內部實現,解決方法很多,只要返回的或賦值的對象不是原引用對象即可。
解決方法:
以Date類型為例:
public void setHappenTime(Date happenTime) {
if(happenTime != null){
this.happenTime = (Date) happenTime.clone();
}else{
this.happenTime = null;
}
}
