异常处理:程序出错了怎么办
程序跑挂了,不能直接蓝屏给用户看。异常(Exception)机制就是 Java 的"保险丝":出错时抛出一个异常对象,你可以选择抓住它、妥善处理,或者继续往上甩。写网络、文件、数据库代码,一半时间都在跟异常打交道。
论受检异常 vs 非受检异常
受检异常(checked):编译器逼着你处理,不 catch 或不 throws 就编译不过。比如 IOException(读文件可能失败)、SQLException(数据库可能断)。
非受检异常(unchecked / RuntimeException):编译器不管,出了事运行时才炸。比如 NullPointerException(空指针,简称 NPE)、IllegalArgumentException、数组越界。
口诀:能预料的外部问题(文件、网络、数据库)用受检异常;自己代码的 bug(空指针、下标越界)是运行时异常,改代码修,别瞎 catch。
try-catch-finally 与 try-with-resources(Java 7+)
import java.io.*;
public class ExceptionDemo {
public static void main(String[] args) {
// 老写法:finally 里手动关流,忘了关就资源泄漏,啰嗦还容易错
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("a.txt"));
System.out.println(reader.readLine());
} catch (IOException e) {
System.out.println("读文件失败:" + e.getMessage());
} finally {
try {
if (reader != null) reader.close();
} catch (IOException ignored) {}
}
// 新写法(推荐):try-with-resources,自动关闭实现了 AutoCloseable 的资源
try (BufferedReader r = new BufferedReader(new FileReader("a.txt"))) {
System.out.println(r.readLine());
} catch (IOException e) {
System.out.println("读文件失败:" + e.getMessage());
}
}
}
异常家族谱系:Exception 和 Error 是两码事
看到抛异常先归类:是 Exception(你代码能处理的)还是 Error(JVM 自己崩了,你救不了)。
| 类型 | 代表 & 怎么对待 |
|---|---|
| Exception | 程序层面的异常,catch 住继续活。又分受检(编译逼你处理)和 RuntimeException(运行时才炸)。 |
| Error | OutOfMemoryError、StackOverflowError——JVM 自身不行了,catch 了也没用,别浪费时间。 |
| RuntimeException 常见兄弟 | NPE、IllegalArgumentException、IndexOutOfBoundsException、ConcurrentModificationException。 |
自定义异常 + throw / throws 的区别
// 自定义异常:业务上"余额不足"这种错,自己定义更清晰
class NotEnoughMoneyException extends Exception {
public NotEnoughMoneyException(String msg) { super(msg); }
}
class Account {
private int balance;
// throws 是在方法签名上"声明":我可能甩这个异常出去,调用者你看着办
public void withdraw(int money) throws NotEnoughMoneyException {
if (money > balance) {
// throw 是"当场抛出"一个异常对象
throw new NotEnoughMoneyException("余额只剩" + balance);
}
balance -= money;
}
}
NullPointerException 就是你对一个 null(空)的对象调用了方法。消除办法:① 返回值别随便给 null,宁可返回空集合 Collections.emptyList();② 判空用 Objects.requireNonNull(x) 或 Optional;③ 调用链上每一步都想一下"这一步会不会是 null"。Java 14+ 还引入了 空指针友好提示,会直接告诉你是哪一步是 null,排错快很多。
1.(概念题)受检异常和非受检异常区别?各举两个例子。
查看答案
答案:受检异常编译器逼你 catch/throws(IOException、SQLException);非受检异常是 RuntimeException 及其子类(NullPointerException、IllegalArgumentException),编译不管。
2.(代码题)throw 和 throws 区别?
查看答案
答案:throw 在方法体里当场抛出一个异常对象;throws 在方法签名上声明"我可能甩这个异常出去",调用者看着办。
3.(代码题)try-with-resources 比 try-finally 好在哪?什么类能放进去?
查看答案
答案:自动关闭资源,不用手写 finally close,不会漏。放进去的类必须实现 AutoCloseable(或 Closeable)。
4.(概念题)Exception 和 Error 区别?看到 OutOfMemoryError 该 catch 吗?
查看答案
答案:Exception 是程序层面可处理的异常;Error 是 JVM 自身崩了(OOME、StackOverflow),catch 了也救不了。别 catch Error,先修堆大小或修代码。