很多 Java 初学者刚接触异常时都会有这样的疑问:
- 什么是异常(Exception)?
- 为什么 Java 要设计异常机制?
- Error 和 Exception 有什么区别?
- Checked Exception 和 RuntimeException 又是什么?
- try、catch、finally、throw、throws 到底有什么区别?
本文将用最通俗的方式,把 Java 异常一次讲明白。
一、什么是 Java 异常?
一句话概括:
Java 异常(Exception)是程序运行过程中发生的错误或异常情况,Java 通过异常机制来发现、传递和处理这些错误,避免程序直接崩溃。
例如:
inta=10;intb=0;System.out.println(a/b);运行结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero因为除数不能为 0,所以 JVM 抛出了一个ArithmeticException(算术异常)。
二、为什么要有异常?
假设 Java 没有异常机制。
程序运行:
程序运行 ↓ 出现错误 ↓ 程序直接退出这样用户只能看到程序崩溃。
而 Java 引入异常后:
程序运行 ↓ 发生错误 ↓ 抛出异常 ↓ 程序捕获异常 ↓ 处理错误 ↓ 程序继续运行例如:
try{intresult=10/0;}catch(Exceptione){System.out.println("出现异常:"+e.getMessage());}System.out.println("程序继续执行");输出:
出现异常:/ by zero 程序继续执行可以看到,虽然发生了错误,但程序并没有直接崩溃,而是继续执行后面的代码。
因此,异常机制的目的就是让程序能够优雅地处理错误,提高程序的健壮性。
三、Java 异常体系
Java 中所有异常最终都继承自Throwable。
整个继承关系如下:
Throwable / \ Error Exception | ---------------------------- | | Checked Exception RuntimeException (编译时异常) (运行时异常)可以看到,Java 的异常主要分为两大类:
- Error(错误)
- Exception(异常)
其中 Exception 又分为:
- Checked Exception(编译时异常)
- RuntimeException(运行时异常)
下面分别介绍。
四、Error(错误)
Error 表示JVM 自身发生了严重错误。
例如:
OutOfMemoryError StackOverflowError举个例子:
publicclassTest{publicstaticvoidtest(){test();}publicstaticvoidmain(String[]args){test();}}由于方法无限递归调用,最终会出现:
StackOverflowErrorError 的特点
- JVM 层面的严重错误
- 一般程序员无法恢复
- 通常不建议使用 try-catch 捕获
一句话记忆:
Error 是 JVM 的严重错误,一般不用程序去处理。
五、Exception(异常)
Exception 表示程序运行过程中可能发生的问题。
例如:
- 文件不存在
- 数据库连接失败
- 空指针
- 数组越界
Exception 又分为两类。
1、Checked Exception(编译时异常)
编译器要求必须处理。
例如:
FileInputStreamfis=newFileInputStream("a.txt");编译器直接报错:
Unhandled exception必须使用:
try{FileInputStreamfis=newFileInputStream("a.txt");}catch(FileNotFoundExceptione){}或者:
publicvoidread()throwsFileNotFoundException{}常见编译时异常:
IOException SQLException ClassNotFoundException一句话:
编译时异常必须处理,否则代码无法通过编译。
2、RuntimeException(运行时异常)
运行时异常编译器不会强制要求处理。
例如数组越界:
int[]arr={1,2};System.out.println(arr[5]);运行结果:
ArrayIndexOutOfBoundsException再例如空指针:
Stringstr=null;System.out.println(str.length());运行:
NullPointerException编译器不会报错。
因为这些异常通常是程序员编写代码时的逻辑错误。
开发中最常见的 RuntimeException 有:
NullPointerException ArithmeticException ArrayIndexOutOfBoundsException ClassCastException NumberFormatException一句话:
运行时异常一般由程序逻辑错误导致,编译器不强制处理。
六、Error 和 Exception 的区别
| Error | Exception |
|---|---|
| JVM 严重错误 | 程序运行异常 |
| 一般无法恢复 | 可以处理 |
| 不建议捕获 | 可以捕获 |
| 例如 OOM | 例如空指针 |
记住一句话:
Error 是 JVM 的问题,Exception 是程序的问题。
七、Java 如何处理异常?
Java 提供了五个关键字:
try catch finally throw throws下面分别介绍。
1、try
放可能发生异常的代码。
try{}2、catch
捕获异常。
例如:
try{inta=10/0;}catch(ArithmeticExceptione){System.out.println("除数不能为0");}程序不会崩溃,而是进入catch。
3、finally
无论是否发生异常都会执行。
try{}finally{}通常用于:
- 关闭数据库连接
- 关闭文件
- 释放资源
例如:
try{}finally{connection.close();}4、throw
主动抛出一个异常对象。
例如:
if(age<0){thrownewIllegalArgumentException("年龄不能小于0");}这里不是 JVM 自动抛异常,而是程序员主动抛。
5、throws
声明方法可能抛出的异常。
例如:
publicvoidreadFile()throwsIOException{}表示:
我这个方法可能会抛出 IOException,调用者需要处理。
八、throw 和 throws 的区别(高频面试)
很多初学者容易混淆。
其实很好记:
| throw | throws |
|---|---|
| 主动抛异常 | 声明异常 |
| 写在方法内部 | 写在方法声明后 |
| 后面跟异常对象 | 后面跟异常类型 |
例如:
thrownewRuntimeException();表示:
主动抛出一个异常对象。
而:
publicvoidtest()throwsIOException{}表示:
告诉调用者,这个方法可能抛 IOException。
一句话:
throw 是抛,throws 是声明。
九、最常见的运行时异常
开发中最容易遇到的就是下面几个。
1、NullPointerException(空指针)
Stringstr=null;str.length();2、ArithmeticException(算术异常)
10/0;3、ArrayIndexOutOfBoundsException(数组越界)
arr[100];4、ClassCastException(类型转换异常)
Animalanimal=newAnimal();Dogdog=(Dog)animal;5、NumberFormatException(数字格式异常)
Integer.parseInt("abc");十、异常是如何传播的?
假设方法调用关系如下:
main() ↓ A() ↓ B() ↓ C()如果:
C()发生异常:
C 不处理 ↓ 抛给 B ↓ B 不处理 ↓ 抛给 A ↓ A 不处理 ↓ 抛给 main ↓ main 不处理 ↓ JVM ↓ 程序结束这就是异常传播机制。
一句话:
异常会沿着方法调用栈一级一级向上传递,直到被处理,否则最终交给 JVM。
十一、面试如何回答?
如果面试官问:
介绍一下 Java 异常。
可以这样回答:
Java 的异常是程序运行过程中出现的异常情况,所有异常都继承自
Throwable。Throwable分为Error和Exception,其中Error表示 JVM 严重错误,一般不处理;Exception表示程序异常,又分为编译时异常和运行时异常。编译时异常必须处理,运行时异常通常由程序逻辑错误导致,不强制处理。Java 提供try-catch-finally、throw、throws等机制来捕获、抛出和传递异常。
这是一个比较完整且面试官认可度较高的回答。
十二、总结
最后用一张图总结整个异常体系。
Throwable / \ Error Exception | ---------------------------- | | Checked Exception RuntimeException (必须处理) (可不处理) 处理方式: try catch finally throw throws记住下面四句话即可:
- Throwable 是所有异常和错误的父类。
- Error 是 JVM 的严重错误,一般不处理。
- Exception 是程序异常,分为编译时异常和运行时异常。
- Java 通过 try-catch、throw、throws 等机制实现异常的捕获、传递和处理。
一句话总结:Java 异常本质上是一套错误处理机制,它将程序运行过程中发生的问题封装成异常对象,通过抛出、传递和捕获异常,让程序能够更加稳定、健壮地运行。