跳转至

异常处理

try/catch/finally 你在 JS 里写过,Java 几乎一样。但 Java 多一个前端人完全陌生的概念:受检异常

基本结构(和 JS 一样)

try {
    riskyCode();
} catch (NumberFormatException e) {   // 捕获特定异常
    System.out.println(e.getMessage());
} finally {
    cleanup();   // 无论如何都执行
}

★ 受检 vs 非受检(这是新概念)

类型 继承 特点 例子
受检异常 Exception 编译器强制 try/catch 或 throws,否则编译不过 IOExceptionSQLException
非受检异常 RuntimeException 和 JS 一样,可不处理 NullPointerExceptionIllegalArgumentException
// readFile 抛受检异常,下面这行不处理就编译报错:
readFile();        // ✗ Unhandled exception BizException

// 必须这样:
try { readFile(); }
catch (BizException e) { ... }

// 或者接着往上甩:
void caller() throws BizException { readFile(); }

为什么要搞受检异常

JS 的异常你忘了 catch 也不会报错,运行时才炸。Java 的受检异常让编译器逼着你面对可能出错的情况(比如 IO、数据库操作),减少了运行时意外。这是 Java"啰嗦但安全"的又一体现。

throws 和 throw

  • throw new XxxException() —— 主动抛出(对标 JS throw)。
  • void f() throws XxxException —— 声明"我可能抛这个异常,调用方要处理"。

自定义异常

class BizException extends Exception {       // 受检
    BizException(String msg) { super(msg); }
}

业务里常用:自定义 BizException 表示"业务错误"(如余额不足),在 Spring 第三篇你会用全局异常处理器统一接住它。

完整可运行示例

package com.javaglm.language.ch11;

/**
 * 第 09 章异常处理。
 * ★ JS 没有的概念:受检异常(checked exception)。
 *   继承 Exception 的异常,编译器强制你要么 try/catch 要么 throws,否则编译不通过。
 *   继承 RuntimeException 的叫非受检异常,和 JS 一样可以不处理。
 */
public class ExceptionDemo {

    public static void main(String[] args) {
        // 1. try / catch / finally:和 JS 几乎一样
        try {
            int[] arr = {1, 2};
            System.out.println(arr[5]);        // 越界,运行时异常
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕获越界:" + e.getMessage());
        } finally {
            System.out.println("finally 无论如何都执行(对标 JS finally)");
        }

        // 2. 受检异常:编译器强制处理。不 try/catch 这行根本编译不过
        try {
            readFile();
        } catch (BizException e) {
            System.out.println("处理受检异常:" + e.getMessage());
        }

        // 3. JDK 7+ 的 multi-catch:一个 catch 抓多种异常
        try {
            int n = Integer.parseInt("abc");
        } catch (NumberFormatException | NullPointerException e) {
            System.out.println("数字格式或空指针:" + e.getMessage());
        }

        // 4. 主动抛出(对标 JS throw)
        try {
            setAge(-1);
        } catch (IllegalArgumentException e) {
            System.out.println("参数非法:" + e.getMessage());
        }
    }

    /** throws 声明:告诉调用方"我可能抛这个受检异常,你必须处理"。 */
    static void readFile() throws BizException {
        throw new BizException("业务异常:文件不存在");
    }

    static void setAge(int age) {
        if (age < 0) {
            // RuntimeException 是非受检异常,不用 throws 声明
            throw new IllegalArgumentException("年龄不能为负:" + age);
        }
    }
}

/** 自定义受检异常:继承 Exception。 */
class BizException extends Exception {
    BizException(String msg) {
        super(msg);
    }
}

前端人对照

JS Java 备注
try/catch/finally 几乎一致
throw new Error() throw new XxxException() Java 异常是类
无受检/非受检之分 受检异常强制处理
catch (e) 抓所有 catch (Exception e) Java 要写异常类型

:octicons-arrow-left-16: 上一章:包与访问修饰符 | 下一章:枚举与包装类