測試發現的是「運行時行為偏離預期」,審查發現的是「靜態代碼結構缺陷」。兩者互補,審查能捕獲邊界條件、線程安全、性能隱患等測試難覆蓋的問題。建立檢查清單,專項獵捕高頻錯誤,事半功倍。
// 差
String s = new String("Text here");
// 好
String s = "Text here"; // 直接用字面量,進入常量池,無新對象開銷
String 不可變,拷貝無意義。
// 差:返回私有引用,調用者可任意修改
public Dimension getSize() { return size; }
// 好:返回防御性拷貝
public Dimension getSize() { return new Dimension(size.width, size.height); }
不可變對象(String、Integer、LocalDate 等)無需拷貝。
// 差
public Integer getValue() { return new Integer(value.intValue()); }
// 好
public Integer getValue() { return value; } // Integer 不可變,直接返回安全
JDK 不可變類:所有包裝類、String、枚舉、LocalDate/Time、大部分異常。
// 差
int[] copy = new int[src.length];
for (int i=0; i
多維數組需深拷貝:for (int i=0; i
// 差:只拷貝數組引用,元素對象共享
Dimension[] copy = dimensions.clone();
// 好:深拷貝每個元素
Dimension[] copy = dimensions.clone();
for (int i=0; i
// 無意義
Object o = new Object();
if (o == null) throw new NullPointerException();
Java new 失敗拋 OutOfMemoryError,不會返回 null。C++ 習慣帶入的錯誤模式。
// 錯
if (str1 == str2) ...
// 對
if (str1.equals(str2)) ...
// 原始類型才用 ==
if (int1 == int2) ...
== 比引用,equals() 比內容。String、包裝類、集合類均重寫了 equals。
// 非線程安全:讀-改-寫三步
count++;
// 線程安全
synchronized void inc() { count++; }
// 或用 AtomicInteger
AtomicInteger count = new AtomicInteger();
count.incrementAndGet();
Java 保證 32 位以內讀寫原子,但復合操作(++、+=)非原子。
// 差:重複代碼、漏捕 Error、close 可能拋異常
try { os = new OutputStream(); ... os.close(); }
catch (Exception e) { if (os!=null) os.close(); }
// 好:finally 保證執行
try { os = new OutputStream(); ... }
finally { if (os!=null) try { os.close(); } catch (IOException ignored) {} }
Java 7+ try-with-resources 更簡潔安全。
// 差
try { ... }
catch (Exception e) { throw e; }
finally { cleanup(); }
// 好:直接 finally
try { ... }
finally { cleanup(); }
只有需包裝異常、記錄日誌、轉換異常類型時才 catch。
equals,子類必須重寫,否則違反對稱性、傳遞性。equals 和 hashCode 必須一致:相等對象 hashCode 相等。clone 需實現 Cloneable、調用 super.clone()、深拷貝可變字段。好的代碼審查不是挑刺,而是傳遞團隊智慧。把「我踩過的坑」變成「你不會踩的坑」,這就是審查的最大價值。