Findbugs
基于Bug Patterns概念,查找java bytecode中的潛在bug。在目前版本中,它不檢查java源檔案。 主要檢查bytecode中的bug patterns,也允許使用者自定義特定的bug patterns。
以下是findbugs的面闆
performance:性能
dodgy code: 不符合規範的代碼
multithreaded correctness: 多線程相關
correctness:代碼的正确性
security:安全性
bad practice: 不好的習慣
experimental: 實驗性問題
internationalization:國際化問題
malicious code vulnerability: 惡意代碼
findbugs右側面闆:
priority代表了嚴重等級,紅色最嚴重,是以我們可以重點關注一下紅色。下方是錯誤詳情。
Bad practice 壞的實踐
一些不好的實踐,下面列舉幾個:
1、類定義了equals(),卻沒有hashCode();。
2、:Statement 的execute方法調用了非常量的字元串;或Prepared Statement是由一個非常量的字元串産生。
3、: 方法終止或不處理異常,一般情況下,異常應該被處理或報告,或被方法抛出。
Correctness 一般的正确性問題
可能導緻錯誤的代碼,下面列舉幾個:
1、: 空指針被引用;在方法的異常路徑裡,空指針被引用;方法沒有檢查參數是否null;null值産生并被引用;null值産生并在方法的異常路徑被引用;傳給方法一個聲明為@NonNull的null參數;方法的傳回值聲明為@NonNull實際是null。
2、: 類定義了hashcode()方法,但實際上并未覆寫父類Object的hashCode();類定義了tostring()方法,但實際上并未覆寫父類Object的toString();很明顯的方法和構造器混淆;方法名容易混淆。
3、:方法嘗試通路一個Prepared Statement的0索引;方法嘗試通路一個ResultSet的0索引。
4、:所有的write都把屬性置成null,這樣所有的讀取都是null,這樣這個屬性是否有必要存在;或屬性從沒有被write。
Internationalization 國際化
當對字元串使用upper或lowercase方法,如果是國際的字元串,可能會不恰當的轉換。
Malicious code vulnerability 惡意代碼
如果代碼公開,可能受到惡意攻擊的代碼,下面列舉幾個:
1、: 一個類的finalize()應該是protected,而不是public的。
2、:屬性是可變的數組;屬性是可變的Hashtable;屬性應該是package protected的。
Multithreaded correctness 多線程的正确性
多線程程式設計時,可能導緻錯誤的代碼,下面列舉幾個:
1、ESync:空的同步塊,很難被正确使用。
2、MWN:錯誤使用notify(),可能導緻IllegalMonitorStateException異常;或錯誤的
使用wait()。
3、: 使用notify()而不是notifyAll(),隻是喚醒一個線程而不是所有等待的線程。
4、: 構造器調用了Thread.start(),當該類被繼承可能會導緻錯誤。
Performance 性能問題
可能導緻性能不佳的代碼,下面列舉幾個:
1、DM:方法調用了低效的Boolean的構造器,而應該用Boolean.valueOf(…);用類似
Integer.toString(1) 代替new Integer(1).toString();方法調用了低效的float的構造器,應該用靜态的valueOf方法。
2、SIC:如果一個内部類想在更廣泛的地方被引用,它應該聲明為static。
3、SS: 如果一個執行個體屬性不被讀取,考慮聲明為static。
4、UrF:如果一個屬性從沒有被read,考慮從類中去掉。
5、UuF:如果一個屬性從沒有被使用,考慮從類中去掉。
Dodgy 不符合規範的,有潛在危險的
具有潛在危險的代碼,可能運作期産生錯誤,下面列舉幾個:
1、CI: 類聲明為final但聲明了protected的屬性。
2、DLS:對一個本地變量指派,但卻沒有讀取該本地變量;本地變量指派成null,卻沒有讀取該本地變量。
3、ICAST: 整型數字相乘結果轉化為長整型數字,應該将整型先轉化為長整型數字再相乘。
4、INT:沒必要的整型數字比較,如X <= Integer.MAX_VALUE。
5、NP: 對readline()的直接引用,而沒有判斷是否null;對方法調用的直接引用,而方法可能傳回null。
6、REC:直接捕獲Exception,而實際上可能是RuntimeException。
7、ST: 從執行個體方法裡直接修改類變量,即static屬性。
舉幾個常見的例子:
bad practice:
1、傳回值沒有檢查的
例:
File f = new File(path + “/capture.json”);
f.delete();
public boolean delete() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkDelete(path);
}
if (isInvalid()) {
return false;
}
return fs.delete(this);
}
類似的還有:f.createNewFile();f.mkdirs();f.setLastModified(currentTime);
f.renameTo(journalFile);等,在使用系統的一些api的時候一定要檢查是否有傳回值,然後根據傳回值判斷是否操作成功。
2、流沒有關閉的
所有的流都要在finally塊裡關閉,以確定不會出現記憶體洩漏
例:
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(
mContext.getAssets().open(fileName)));
String line;
while ((line = bf.readLine()) != null) {
stringBuilder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
這樣是不規範的,應該如下:
try {
bf = new BufferedReader(new InputStreamReader(
mContext.getAssets().open(fileName)));
String line;
while ((line = bf.readLine()) != null) {
stringBuilder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bf!=null){
try {
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、定義了equals卻沒有定義hascode
如圖:
4、字元串比較要用equals而不是等于号 ==
5、序列化的類裡面定義了一個非序列化的字段,沒有定義序列化ID
public class SaveCoverInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String apiVersion;
private DataBean data;
public String getApiVersion() {
return apiVersion;
}
public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}
public DataBean getData() {
return data;
}
public void setData(DataBean data) {
this.data = data;
}
public static class DataBean implements Serializable{
private String img1;
public String getImg1() {
return img1;
}
public void setImg1(String img1) {
this.img1 = img1;
}
}
}
6、get/set方法沒有用到的
7、調用parsexxx比valueof效率高:
long date = Long.valueOf(dataMap.get(columnName));
應該寫成:
long date = Long.parseLong(dataMap.get(columnName));
8、頻繁裝箱拆箱的
public Boolean getFieldValue(String fieldStringValue) {
if (TextUtils.isEmpty(fieldStringValue)) return null;
return fieldStringValue.length() == 1 ? “1”.equals(fieldStringValue) : Boolean.valueOf(fieldStringValue);
}
9、使用對象前沒有判斷空指針的
10、switch語句沒有定義default的
還有很多其它類型的優化建議,就不再舉例了,大家可以在使用findbugs的過程中慢慢發現總結(#.#)