代碼審查是消滅 Bug 最有效手段之一,能發現測試難覆蓋的細節錯誤。本文整理 11 類 Java 常見審查盲點,建議加入團隊 Checklist。
// ❌ 多餘
String s = new String("Text here");
String s2 = new String(temp);
// ✅ 直接引用常量池
String s = "Text here";
原則:String、包裝類型、BigInteger 等不可變物件無需拷貝,直接傳回參考即可。
// ❌ 危險
private Dimension d = new Dimension(0,0);
public Dimension getValues() { return d; } // 呼叫端可任意修改 d.width/height
// ✅ 回傳防禦性拷貝
public Dimension getValues() { return new Dimension(d.width, d.height); }
// ✅ 或回傳不可變視圖(Java 8+)
public List getTags() { return Collections.unmodifiableList(tags); }
// ❌ 多餘
private Integer i = 0;
public Integer getValue() { return new Integer(i.intValue()); }
// ✅ 直接回傳
public Integer getValue() { return i; }
判斷依據:類別是否為 final 且無可變方法(String、所有基本型別包裝類、BigDecimal 等)。
// ❌ 低效、易出錯
int[] copy = new int[src.length];
for (int i = 0; i < src.length; i++) copy[i] = src[i];
// ✅ 標準庫
int[] copy = src.clone(); // 基本型別/物件參考淺拷貝
int[] copy = Arrays.copyOf(src, src.length);
int[] copy = Arrays.copyOfRange(src, 0, src.length);
System.arraycopy(src, 0, copy, 0, src.length); // 效能最佳
equals() 未處理 null、未檢查型別、未覆寫 hashCode()// ✅ 標準範本
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyClass that = (MyClass) o;
return Objects.equals(field1, that.field1) &&
Objects.equals(field2, that.field2);
}
@Override
public int hashCode() { return Objects.hash(field1, field2); }
compareTo() 與 equals() 不一致實作 Comparable 時,a.compareTo(b) == 0 應蘊含 a.equals(b) == true,否則 TreeSet/TreeMap 行為異常。
finally 區塊回傳值/拋異常// ❌ 吞噬原始異常
try { risky(); } finally { return defaultVal; }
// ✅ 正確
try { return risky(); } finally { cleanup(); }
HashMap 鍵為可變物件且修改後未重新放入修改鍵物件的 hashCode() 相關欄位會導致找不到原 Entry。鍵必須不可變,或修改後 remove -> put。
SimpleDateFormat 宣告為靜態共用(非執行緒安全)// ❌ 併發環境下會產生亂碼/拋異常
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
// ✅ ThreadLocal 或 Java 8 DateTimeFormatter
private static final ThreadLocal TL = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
// 或
private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 不可變、執行緒安全
throw new MyException(e.getMessage()))
// ❌ 丟失原始堆疊
catch (SQLException e) { throw new DaoException(e.getMessage()); }
// ✅ 保留因果鏈
catch (SQLException e) { throw new DaoException("查詢失敗", e); }
// ✅ Java 7+ try-with-resources
try (Connection c = ds.getConnection();
PreparedStatement ps = c.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
// 使用資源
} // 自動關閉,即使拋異常
將這 11 項納入團隊 Code Review Checklist,配合 SonarQube/SpotBugs 靜態分析,可大幅降低生產事故率。