數組之間的拷貝使用System.arrayCopy更加高效java
byte[] ReceiveBytes = new byte[length1+ length2];
for (int i = 0; i < length1; i++) {
ReceiveBytes[i] =ReceiveBytes_temp1[i];
}正則表達式
避免建立已經存在的Big Integer對象 ,如:(BigDecimal.ZERO,BigDecimal.ONE, BigDecimal.TEN)spring
避免建立已經存在的Boolean 對象;如:Boolean.TRUE, Boolean.FALSEexpress
有Final修飾符的成員變量必須是靜態的數組
避免顯示調用垃圾回收緩存
低效利用使用keySet迭代器而不是entrySet迭代器。安全
使用entrySet效率會比keySet高app
for (String key : map.keySet()) {框架
//to do some thingless
}
for (Entry entry : map.entrySet()) {
//to do some thing
}
避免在循環中使用「+」 鏈接字符串。使用Stringbuffer 或Stringbuilder
定義爲Private類型方法從未被調用,應該被刪除
使用ArrayList 替換Vector
若是從數組轉換成一個List,用Arrays. AsList() 替換遍歷數組的形式轉換
避免建立無用的局部變量,如:
String s = getxx();
return s;
直接替換爲return getxx();
當參數是單個字符的時候使用 String.indexOf(char)替換String.indexOf(String)
好比:用s.indexOf(‘a‘) 代替s.indexOf(「a」)
如:String s = new String();
正確寫法 String s = 「」;
如:String s = new String(「test」);
正確寫法 String s = 「test」;
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
對原始值進行裝箱而後當即把它強制轉換爲另一種原始類型。例如:
new Double(d).intValue()應該直接進行強制轉換例如:(int)d
無用的包導入
無用的局部變量
未用的常規參數:避免傳遞給方法或構造器不使用的參數
代碼中包含TODO註釋
避免使用空代碼塊
有時候兩個 if 語句能夠經過布爾短路操做符分隔條件表達式組合成一條語句
如:
If(a==b){
If(c==1){
//do some thing
}
}
避免在 BigDecimal 類型的構造方法中用小數類型的字面量:人們經常以
爲」new BigDecimal(0.1)」能精確等於 0.1, 其實否則,它等於「 0. 1000000000000000055511151231257827021181583404541015625 」,這 種情況的緣由是 0.1 不能精確的表示雙精度類型,所以,傳入構造器的 long 類型不等於 0.1 ,而傳入 String 類型的構造器 new BigDecimal(「0.1」) 能夠精確等於 0.1, 故推薦這種情形時用 String 類型的構造器
破壞空檢查:若是自身拋出空指針異常空檢查就會遭到破壞,好比你使用 || 代替 && ,反之亦然。
if (string!=null ||!string.equals("")) { // 這裏應該是&&
return string;
}
關閉資源:確保這些資源(譬如:Connection,Statement,和 ResultSet 對象)總在使用後被關閉
對象相等性比較:使用 equals()比較對象的引用,避免使用」==」來比較
String的split,replaceAll等方法傳遞的參數是正則表達式,正則表達式自己用到的字符須要轉義,如:句點符號「.」,美圓符號「$」,乘方符號「^」,大括號「{}」,方括號「[]」,圓括號「()」,豎線「|」,星號「*」,加號「+」,問號「?」等等,這些須要在前面加上「\\」轉義符。
如:s = s.replaceAll(".", "/"); 應該使用s =s.replaceAll("\\.", "/");
明顯的無限循環
明顯的無限迭代循環,將致使堆棧溢出
重寫equals 後必須重寫hashCode
避免equals()方法和 null 比較
單元測試必須包含斷言,而不是簡單的打印結果後看輸出。
對於不變類型的無用操做:對於不變類型對象 (String,BigDecimal 或BigInteger) 的操做不會改變對象自己,但操做結果是產生新的對象,因此操做的結果是錯的
如:BigDecimal a=new BigDecimal(10);
a.add(newBigDecimal(5));
正確的寫法:
BigDecimal bd=new BigDecimal(10);
bd = bd.add(new BigDecimal(5));
避免用== or != 比較 String
StringBuffer sb = new StringBuffer('c');
字符 c 會轉換爲 int 值,做爲 StringBuffer 的初始化大小參數
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輸出中直接寫入一個HTTP參數,這會形成一個跨站點的腳本漏洞
private static SimpleDateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");
避免使用靜態的DateFormat,DateFormat 是非線程安全的
同上
清空集合使用clear() 代替removeAll()
在代碼中避免使用e.printStackTrace,使用logger代替
代碼中禁止使用System.println
While for 循環If Else 代碼塊必須使用大括號
爲局部變量賦值,但在其後的沒有對她作任何使用。一般,這代表一個錯誤,由於值從未使用過。
此方法使用相同的代碼,以實現兩個有條件的分支。檢查以確保這是否是一個編碼錯誤
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;
} }