异常与泛型
异常
Java的所有异常和错误都继承自 java.lang.Throwable类。分为两大分支:
- Error:系统级错误,程序无法处理(如
OutOfMemoryError) - Exception:程序可处理的异常
- Checked Exception:编译时强制检查、必须被捕获或声明抛出(如
IOException、ClassNotFoundException) - Unchecked Exception:运行时异常、不强制处理(如
NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException)
- Checked Exception:编译时强制检查、必须被捕获或声明抛出(如

异常处理关键字
try:包裹可能发生异常的代码块。
catch:捕获特定类型的异常并进行处理。可以有多个catch块,子类异常必须写在父类前面(否则会编译错误)。
finally:无论是否发生异常,必定会执行的代码块。常用于释放资源(如关闭文件、网络连接)。
throw:在方法内部手动抛出一个异常对象。
throws:在方法声明上,指明该方法可能抛出的异常类型,通知调用者需要处理。
| 特性 | throw | throws |
|---|---|---|
| 作用 | 主动抛出一个具体的异常对象 | 声明方法可能抛出的异常类型 |
| 语法位置 | 方法内部使用 | 方法签名末尾使用 |
| 数量 | 一次只能抛出一个异常对象 | 可以声明多个异常类型(逗号分隔) |
| 处理方式 | 必须配合try-catch或throws使用 | 调用者必须处理(try-catch或继续throws) |
Error和Exception的区别?
Error是程序无法处理的严重系统错误,如OOM,应用程序无需捕获。Exception是程序可以处理的异常,分为受检异常(必须处理)和非受检异常(运行时异常,可不处理)。
Checked Exception和Unchecked Exception的区别?
- 受检异常:编译器强制检查,必须用
try-catch捕获或用throws声明抛出。通常是由外部因素(如I/O错误、文件不存在)导致的可恢复问题。- 非受检异常:编译器不检查,无需强制处理。通常是程序逻辑错误(如空指针、数组越界),属于不可恢复的错误。
finally块一定会执行吗?什么情况下不执行?
几乎一定会执行。只有在以下极端情况下不会:
- System.exit()被调用
- 线程死亡
- JVM崩溃
- 服务器断电、系统崩溃等物理原因。
在finally块中写return语句会怎样?
严禁这样做。它会覆盖
try或catch块中的返回值,并抑制其他异常的抛出,导致极其隐蔽的BUG,且编译器会产生警告。
try-catch-finally的执行顺序?如果catch中又抛出了异常呢?
顺序是
try-> 如果发生异常则进入匹配的catch-> 最后必定执行finally。如果在catch中抛出了新异常,这个新异常会在finally执行完后才被抛出。
什么是异常链?有什么好处?
异常链是将捕获的原始异常作为原因(Cause)传递给新的异常。好处是能保留完整的异常堆栈信息,便于追踪问题的根本原因,不会因为抛出新的业务异常而丢失底层的详细错误。
用过try-with-resources吗?它有什么好处?
它用于自动管理资源,确保每个资源在语句结束时都被正确关闭。好处是代码更简洁,避免了繁琐的
finally块和手动关闭,并且能更好地处理“关闭异常”( suppressed exceptions)。
异常使用注意点
- 不要把异常定义为静态变量,因为这样会导致异常栈信息错乱。每次手动抛出异常,我们都需要手动 new 一个异常对象抛出。
- 抛出的异常信息一定要有意义。
- 建议抛出更加具体的异常,比如字符串转换为数字格式错误的时候应该抛出
NumberFormatException而不是其父类IllegalArgumentException。 - 避免重复记录日志:如果在捕获异常的地方已经记录了足够的信息(包括异常类型、错误信息和堆栈跟踪等),那么在业务代码中再次抛出这个异常时,就不应该再次记录相同的错误信息。重复记录日志会使得日志文件膨胀,并且可能会掩盖问题的实际原因,使得问题更难以追踪和解决
泛型
Java 泛型(Generics) 是 JDK 5 中引入的一个新特性。使用泛型参数,可以增强代码的可读性以及稳定性。使用方式:泛型类、泛型接口、泛型方法。
编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。比如 ArrayList<Person> persons = new ArrayList<Person>() 这行代码就指明了该 ArrayList 对象只能传入 Person 对象,如果传入其他类型的对象就会报错
类型擦除
编译时检查,运行时擦除:泛型信息只存在于编译阶段,运行时JVM看到的都是原始类型(Raw Type)
擦除规则:
- 无界类型参数
<T>→Object - 有界类型参数
<T extends Number>→Number - 泛型方法参数类型同样被擦除
- 无界类型参数
