測量優於猜測,可讀性優於微優化,架構優於局部。
—— 任何優化前請先 Profiling(JProfiler、Async Profiler、Arthas),找到真正熱點再下手。
// ❌ 迴圈中產生大量臨時 String 對象
String result = "";
for (String s : list) result += s;
// ✅ 單線程用 StringBuilder,多線程用 StringBuffer
StringBuilder sb = new StringBuilder(list.size() * 16); // 預估容量
for (String s : list) sb.append(s);
String result = sb.toString();
原理: + 編譯器雖優化為 StringBuilder,但迴圈中每次仍 new Builder + toString,產生大量短命對象,增加 Young GC 壓力。
// ✅ 棧上分配,隨棧幀銷毀,無 GC 開銷
void process() {
String prefix = "gebi"; // 局部變量
if ("laowang".equals(name)) {
list.add(prefix + name);
}
}
原理: 局部變量存棧,生命週期隨方法結束;堆上對象需 GC 回收,分配/回收皆有開銷。
// ❌ 每次迴圈 new Object()
while (i < 1000) { Object obj = new Object(); }
// ✅ 引用復用,僅分配 1 個引用變量
Object obj = null;
while (i < 1000) { obj = new Object(); }
// ✅ 避免多次擴容複製
List<User> users = new ArrayList<>(expectedSize);
Map<Long, Order> map = new HashMap<>((int)(expectedSize / 0.75f) + 1);
// ✅ 單次查找,O(1)
for (Map.Entry<K, V> entry : map.entrySet()) {
K k = entry.getKey(); V v = entry.getValue();
}
// ❌ keySet 需再 map.get(key),雙重查找
for (K k : map.keySet()) { V v = map.get(k); }
Iterator(避免隱式 lambda 物件、棧幀開銷)forEach / Stream API// ✅ BufferedInputStream/Reader 包裹,減少系統調用
try (BufferedReader br = new BufferedReader(new FileReader(file))) { ... }
使用 try-with-resources 確保釋放,避免句柄洩漏導致系統資源耗盡。
// ❌ 迴圈內 try-catch,JIT 難優化、棧追蹤開銷大
for (Item item : items) {
try { process(item); } catch (Exception e) { log(e); }
}
// ✅ 迴圈外統一捕獲,或 process 內部處理
try {
for (Item item : items) process(item);
} catch (Exception e) { log(e); }
僅包裹可能拋檢查異常的代碼,避免污染熱點路徑的 JIT 優化(如內聯、逃逸分析)。
static final,編譯器常量折疊優化。// ✅ 細粒度鎖
private final Object lock = new Object();
public void update() {
synchronized (lock) { /* 僅保護共享狀態 */ }
}
// ✅ 高併發用 ConcurrentHashMap、LongAdder、ThreadLocal
ConcurrentHashMap<K, V> map = new ConcurrentHashMap<>();
LongAdder counter = new LongAdder(); // 優於 AtomicLong
JDK 8+ 預設開啟 -XX:+DoEscapeAnalysis,未逃逸對象可標量替換(拆解為局部變量)、棧上分配、同步消除。寫法:方法內 new 對象、不傳遞給外部。
// ✅ 避免裝箱/拆箱開銷
int sum = 0;
for (int i = 0; i < 10000; i++) sum += i;
// ❌ Integer 自動裝箱拆箱
Integer sum = 0;
for (int i = 0; i < 10000; i++) sum += i;
Integer i = 1;
// 效能:i.toString() > String.valueOf(i) > "" + i
// 原因:""+i 編譯為 StringBuilder.append(i).toString(),多一次 Builder 創建
| 類別 | 檢查項 | 工具/驗證 |
|---|---|---|
| 對象分配 | 熱點方法分配率、大對象直接進老年代 | JProfiler / Async Profiler / arthas heapdump |
| GC | Young/Old GC 頻率、停頓時間、記憶體佔用曲線 | GC Log + GCViewer / Arthas dashboard |
| 鎖爭用 | 同步塊耗時、阻塞線程數 | JProfiler Monitor / Arthas thread -b |
| I/O | 系統調用次數、緩衝區大小 | strace / perf / Java Flight Recorder |
| JIT | 熱點方法編譯狀態、內聯情況 | -XX:+PrintCompilation / JITWatch |
掌握這 15 條模式,配合工具驅動優化,你的 Java 代碼將在效能與可維護性間達到最佳平衡。