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

Java 核心異常體系:RuntimeException 常見類型、成因與處理策略

     編輯:Java 綜合教學

異常體系速覽

Throwable
├── Error (嚴重錯誤,不可恢復:OOM、StackOverflow、ClassFormatError)
└── Exception (可捕獲處理)
    ├── RuntimeException (非檢查異常,編譯器不強制處理)
    │   ├── NullPointerException
    │   ├── ClassCastException
    │   ├── IllegalArgumentException
    │   ├── IndexOutOfBoundsException
    │   ├── ArithmeticException
    │   ├── NumberFormatException
    │   ├── ConcurrentModificationException
    │   └── UnsupportedOperationException
    └── Checked Exceptions (檢查異常,必須 try-catch 或 throws)
        ├── IOException
        ├── SQLException
        ├── ClassNotFoundException
        ├── InterruptedException
        └── NoSuchMethodException

高頻 RuntimeException 詳細檔案

異常典型成因代碼示例預防/處理
NullPointerException呼叫 null 物件的方法/屬性、陣列元素為 null、自動拆箱 nullString s = null; s.length();
Integer i = null; int n = i;
@NotNull 驗證、Optional、Objects.requireNonNull、防禦性檢查
ClassCastException強制轉型不相容類型、泛型擦除導致運行期轉型失敗Object o = new ArrayList(); String s = (String) o;instanceof 守衛、編譯期泛型約束、避免原始類型
IllegalArgumentException傳遞不符合預期的參數 (負數、空字串、超出範圍)setAge(-5); thread.sleep(-100);參數驗證 (Bean Validation @Min/@Max)、Preconditions.checkArgument
IndexOutOfBoundsException陣列/列表/字串索引越界 (負數或 ≥ size)list.get(10); // size=5
str.charAt(-1);
邊界檢查、for-each 替代索引、List.getOrDefault()
ArithmeticException整數除以零、BigDecimal 非終結小數除法無精度設定int x = 10 / 0;
BigDecimal.ONE.divide(BigDecimal.valueOf(3))
除數檢查、BigDecimal.divide(divisor, scale, RoundingMode)
NumberFormatException字串解析為數字格式錯誤 (含空格、非數字字元、溢位)Integer.parseInt("12a3");
Long.parseLong("");
正則預檢、try-catch 包裝、NumberUtils.isParsable()
ConcurrentModificationException迭代器遍歷時集合被修改 (單執行緒或多執行緒)for (String s : list) { if (s.equals("x")) list.remove(s); }Iterator.remove()、CopyOnWriteArrayList、CompletableFuture.allOf、Stream API
UnsupportedOperationException調用不可選操作 (Arrays.asList().add()、Collections.unmodifiableList().add())List.of(1,2).add(3);使用可變列表 new ArrayList<>(List.of(...))、檢查文檔
ArrayStoreException陣列存入非相容類型 (Object[] arr = new String[1]; arr[0] = new Integer(1);)Object[] arr = new String[1]; arr[0] = 1;避免陣列協變、使用 List<T>、泛型陣列工廠模式
NegativeArraySizeException建立負長度陣列 new int[-5]int size = -1; new byte[size];長度參數驗證 if (size < 0) throw new IllegalArgumentException()

Error 類 (不可恢復,通常不捕獲)

Error成因應對
OutOfMemoryError堆/元空間/直接記憶體耗盡、記憶體洩漏、堆過小分析 Heap Dump (MAT)、調大 -Xmx、修復洩漏、檢查 Metaspace
StackOverflowError遞歸過深、循環調用、線程棧過小 (-Xss)改迭代、尾遞歸優化、增大 -Xss、檢查循環依賴
NoClassDefFoundError類載入失敗 (依賴缺失、靜態初始化拋異常、類路徑衝突)檢查依賴傳遞、mvn dependency:tree、排除衝突版本
UnsatisfiedLinkErrorJNI 本地庫找不到 (路徑錯、架構不匹配、庫缺失)配置 java.library.path、確認 32/64 位匹配
VerifyError / ClassFormatError字節碼損壞、版本不兼容 (高版本編譯低版本運行)統一 JDK 版本、清理 target、檢查編譯目標版本

Checked Exception 代表 (必須處理)

異常場景處理策略
IOException檔案/網路/流操作失敗try-with-resources、重試機制、熔斷器
SQLException資料庫操作失敗事務回滾、連線池驗證、死鎖重試
ClassNotFoundException反射/動態載入類失敗檢查類路徑、模組系統 opens、依賴管理
InterruptedException線程睡眠/等待被中斷重置中斷旗標 Thread.currentThread().interrupt()、拋出或終止任務
TimeoutExceptionFuture.get(timeout)、連線/讀取超時超時重試、降級、熔斷

異常處理最佳實踐

  1. 具體捕獲:catch (SQLException | IOException e) 而非 catch (Exception e)。
  2. 異常鏈保留:throw new BusinessException("訂單建立失敗", e) 保留根因堆疊。
  3. 不吞噬異常:空 catch 塊是大忌,至少記錄日誌。
  4. 業務異常封裝:自訂 BusinessException(code, message),控制器統一處理返回標準錯誤碼。
  5. 資源確實釋放:try (Resource r = acquire()) { ... } 自動關閉。
  6. 避免流程控制用異常:異常成本高,業務判斷用條件檢查。
  7. 全局異常處理:@RestControllerAdvice + @ExceptionHandler 統一響應格式。
  8. 日誌記錄原則:log.error("業務失敗", e) 而非 log.error(e.getMessage()) (丟失堆疊)。

自訂業務異常範例

@Getter
public class BusinessException extends RuntimeException {
    private final int code;
    private final String userMessage;

    public BusinessException(ErrorCode errorCode, String... args) {
        super(errorCode.getMessage(args));
        this.code = errorCode.getCode();
        this.userMessage = errorCode.getMessage(args);
    }

    public static BusinessException of(ErrorCode errorCode, Object... args) {
        return new BusinessException(errorCode, args);
    }
}

public enum ErrorCode {
    ORDER_NOT_FOUND(4001, "訂單不存在: {0}"),
    INSUFFICIENT_STOCK(4002, "庫存不足: 商品 {0} 僅剩 {1} 件"),
    PAYMENT_FAILED(4003, "支付失敗: {0}");

    private final int code;
    private final String template;
    ErrorCode(int code, String template) { this.code = code; this.template = template; }
    public String getMessage(Object... args) { return MessageFormat.format(template, args); }
}

全局異常處理器

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ApiResponse<Void>> handleBusiness(BusinessException e) {
        log.warn("業務異常: code={}, msg={}", e.getCode(), e.getUserMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
            .body(ApiResponse.error(e.getCode(), e.getUserMessage()));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResponse<Void>> handleValidation(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldErrors().stream()
            .map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
            .collect(Collectors.joining("; "));
        return ResponseEntity.badRequest().body(ApiResponse.error(4000, msg));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Void>> handleUnknown(Exception e) {
        log.error("系統異常", e);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(ApiResponse.error(5000, "系統內部錯誤,請稍後再試"));
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved