下面把“Java 异常处理基础”拆成 8 个你必须掌握的小点,每个都给出代码片段,复制即可跑。看完就能应付 90% 的入门面试与日常编码。

异常体系一览(记住这张图就够了)

Throwable
 ├─ Error(JVM 错误,代码不处理)
 └─ Exception
     ├─ RuntimeException(非受检异常,可不用 try-catch)
     │   ├─ NullPointerException
     │   ├─ ArrayIndexOutOfBoundsException
     │   └─ ...
     └─ 受检异常(必须处理)
         ├─ IOException
         ├─ SQLException
         └─ ...

受检 vs 非受检

  • 受检(Checked):编译器强制你处理,要么 try-catch,要么 throws 声明。

  • 非受检(Unchecked):RuntimeException 子类,编译器不管,运行时才爆。

入门模板:try-catch-finally

public static int divide(int a, int b) {
    try {
        return a / b;               // 可能抛出 ArithmeticException
    } catch (ArithmeticException e) {
        System.out.println("除零了:" + e.getMessage());
        return -1;                  // 异常时的返回值
    } finally {
        System.out.println("finally 永远执行,用于释放资源");
    }
}

多重 catch & 合并写法(JDK 7+)

try {
    int x = Integer.parseInt("abc");
} catch (NumberFormatException | NullPointerException e) { // 合并
    System.out.println("数字转换或空指针");
}

注意:合并时异常变量 e 是 final,不能重新赋值。

throws 向上抛

public void readFile(String path) throws IOException { // 受检异常不处理,交给上层
    Files.readAllBytes(Paths.get(path));
}

手动抛异常:throw

public void setAge(int age) {
    if (age < 0) throw new IllegalArgumentException("年龄不能负数");
}

IllegalArgumentException 是 RuntimeException 子类,属于非受检。

自定义异常(两步走)

// 1. 继承 Exception 或 RuntimeException
public class ScoreException extends Exception {
    public ScoreException(String msg) { super(msg); }
}

// 2. 使用
public void check(int score) throws ScoreException {
    if (score < 0 || score > 100) throw new ScoreException("分数非法");
}

业务语义更清晰,上层可精准 catch(ScoreException)。

面试高频陷阱题

public static int test() {
    try {
        return 1;
    } finally {
        return 2;   // 会覆盖 try 中的 1
    }
}
// 结果:2。finally 里别写 return!

try-with-resources(自动关流,JDK 7+)

public static void copy(String src, String dst) throws IOException {
    try (InputStream in = new FileInputStream(src);
         OutputStream out = new FileOutputStream(dst)) {
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
    } // 自动调用 in.close()、out.close(),无论是否异常
}

资源类必须实现 java.lang.AutoCloseable。

异常链(保留根因)

try {
    Integer.parseInt("abc");
} catch (NumberFormatException e) {
    throw new RuntimeException("包装后抛出新异常", e); // 把 e 传进去,根因不丢
}

调试时打印完整栈链:e.printStackTrace();

速记口诀
“受检必须抓,运行可不管;
finally 先执行,return 会覆盖;
try-with-resources,自动关流真香。”

更多推荐