許多開發者擔心 `try-catch` 影響效能而避免使用異常。OneAPM 實測發現:**單純拋出與捕獲異常成本極低(~0.02 ms/次)**,真正拖垮效能的是:**收集堆疊追蹤** 與 **異常處理中的補償代碼**(重試、回滾、降級邏輯)。
實驗設計
- 基準:簡單迴圈隨機拋出/捕獲自訂異常。
- 結果:每次異常約 0.02 毫秒,除非拋出 >10 萬次,否則可忽略。
- 加入 `exception.printStackTrace()` 或 `getStackTrace()` → **效能影響放大 10 倍**。
- 多層架構下(Web Client → Framework → Business Logic)同一錯誤被層層包裝、重新拋出,產生多組堆疊追蹤,寫入日誌 I/O 更是雪上加霜。
關鍵發現
- 異常機制本身不慢,JVM 對異常路徑優化良好(HotSpot 編譯器會優化熱點路徑)。
- 堆疊追蹤收集昂貴:需走訪呼叫堆疊、格式化字串、分配記憶體。
- 補償代碼才是大頭:重試連線、資料庫回滾、降級預設值、發送告警等業務邏輯才消耗真正資源。
- 濫用異常控制流程(如用異常跳出迴圈)會導致大量堆疊追蹤生成,嚴重拖慢效能。
最佳實踐建議
- ✅ **異常用於「異常情況」**(錯誤、失敗、不可預期狀態),而非正常控制流程。
- ✅ **避免在迴圈/高頻路徑拋出異常**,改用回傳值/Optional/Result 型別。
- ✅ **僅在需要診斷時收集堆疊追蹤**(記錄日誌層級 ERROR/WARN),INFO/DEBUG 層級勿收集。
- ✅ **統一異常處理層**(ControllerAdvice、Filter、Middleware)集中記錄、轉換、回應,避免各層重複 `printStackTrace`。
- ✅ **監控異常頻率**(APM 工具如 OneAPM、SkyWalking、Pinpoint),異常率突增即時告警。
- ✅ **自訂異常類別攜帶業務錯誤碼**,減少堆疊追蹤依賴,前端依錯誤碼顯示友善訊息。
圖文示範

結論
不要因為效能迷思而放棄異常機制。**正確使用異常能寫出更乾淨、可維護的代碼**。真正要優化的是:減少不必要的堆疊追蹤收集、簡化補償邏輯、避免異常濫用於控制流程。