首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 異常處理三層次:優、劣、惡實戰對比

     編輯:Java 相關知識

基礎概念速查

  • Checked Exception:繼承 Exception 非 RuntimeException,編譯器強制 try-catch 或 throws(如 IOException)
  • Unchecked Exception:RuntimeException 及其子類、Error,編譯器不強制,通常表示編程錯誤或系統級故障
  • throws 原則:方法內拋出 checked 異常(調用拋出方法、主動 throw)必須聲明;unchecked 可不聲明

層次一:惡劣 —— 吞噬異常 / 濫用 catch-all

// 惡劣 1:捕獲後什麼都不做
try { risky(); } catch (Exception e) { /* 空 */ }

// 惡劣 2:捕獲 Exception 甚至 Throwable
try { ... } catch (Throwable t) { log(t); } // 掩蓋 Error,導致 JVM 關鍵故障被忽略

// 惡劣 3:異常作控制流
try { int i = map.get(key); } catch (NullPointerException e) { i = defaultValue; } // 應用 map.containsKey()

後果:Bug 隱匿、根因丟失、性能損耗、維護噩夢。

層次二:不好 —— 機械式處理 / 信息丟失

// 不好 1:只打印堆棧,繼續執行導致後續 NPE
try { InputStream in = new FileInputStream(f); } catch (FileNotFoundException e) { e.printStackTrace(); }
in.read(); // 此處 in 為 null → NPE

// 不好 2:包裝異常丟失原始堆棧
try { ... } catch (SQLException e) { throw new RuntimeException(e.getMessage()); } // 無 cause

// 不好 3:過度寬泛 throws
public void doAll() throws IOException, SQLException, TimeoutException, ParseException { ... } // 調用者無法針對性處理

層次三:優秀 —— 精準、信息豐富、可恢復

// 優 1:精準捕獲,業務語義包裝,保留因果鏈
try {
    return parseConfig(file);
} catch (IOException e) {
    throw new ConfigLoadException("無法讀取配置:" + file, e); // 自定義異常攜帶原因
} catch (ParseException e) {
    throw new ConfigLoadException("配置格式錯誤:" + file, e);
}

// 優 2:try-with-resources 確保資源釋放,異常自動抑制
public String readFirstLine(Path path) throws IOException {
    try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
        return br.readLine();
    }
}

// 優 3:異常轉換邊界清晰:持久層 → 服務層 → 控制層
@Repository
public class UserDao {
    public User findById(Long id) {
        try { return jdbc.queryForObject(sql, mapper, id); }
        catch (EmptyResultDataAccessException e) { return null; } // 正常業務:不存在
        catch (DataAccessException e) { throw new PersistenceException("DB錯誤", e); } // 異常:包裝上拋
    }
}

@Service
public class UserService {
    public UserDTO getUser(Long id) {
        User u = dao.findById(id);
        if (u == null) throw new UserNotFoundException(id); // 業務異常
        return mapper.toDTO(u);
    }
}

@RestControllerAdvice
public class GlobalHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity handle(UserNotFoundException e) {
        return ResponseEntity.status(404).body(new ErrorResp("USER_NOT_FOUND", e.getMessage()));
    }
    @ExceptionHandler(PersistenceException.class)
    public ResponseEntity handle(PersistenceException e) {
        log.error("持久層故障", e); // 記錄完整堆棧
        return ResponseEntity.status(500).body(new ErrorResp("SYSTEM_ERROR", "服務暫時不可用"));
    }
}

自定義異常設計規範

  • 繼承 RuntimeException(業務異常)或 Exception(可恢復受檢異常)
  • 提供構造器:message、message + cause、cause
  • 攜帶業務上下文字段:userId, orderNo, errorCode
  • 命名以 Exception 結尾,語義清晰:InsufficientBalanceException

日誌與監控最佳實踐

  • 業務異常 WARN 級別記錄關鍵信息(不打印全棧)
  • 系統異常 ERROR 級別記錄完整堆棧 + 關鍵參數
  • 接入 APM(SkyWalking、Pinpoint)自動關聯調用鏈
  • 關鍵異常設置告警(熔斷器觸發、數據庫連接池耗盡等)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved