【Java】Java 异常处理机制详解
大家好,最近整理了 Java 异常相关的知识点,今天系统和大家分享一下 Java 的异常处理机制。异常是开发中避不开的内容,合理处理异常能让程序更加健壮,避免无故崩溃。
一、什么是异常
简单来说,异常就是打断程序正常执行流程的意外事件。程序按照既定逻辑运行时,一旦出现异常,代码就会终止执行。如果不做任何处理,程序会直接闪退。
而 Java 提供了完善的异常处理体系,我们可以主动捕获、处理异常,既保证核心业务继续运行,也能给用户友好的提示。
二、Error 与 Exception 的区别
Java 中所有异常和错误的顶层父类是Throwable,它主要分为两大分支:Error和Exception。
- Error(错误)属于系统级别的严重问题,通常是虚拟机、硬件层面引发的致命错误,代码层面无法捕获和处理。比如内存溢出、虚拟机崩溃等,一旦出现,程序基本无法恢复。示例:
OutOfMemoryError(内存溢出错误)。 - Exception(异常)这是我们日常开发重点关注的部分,代表程序运行中出现的可修复问题,我们可以通过代码主动捕获、处理。比如除数为 0、空指针、文件不存在等。
三、受检异常与运行时异常
Exception又分为Checked 受检异常和Unchecked 非受检异常(运行时异常)。
1. Checked 受检异常
编译阶段就会被编译器检查,必须显式捕获或者向上抛出,否则代码直接编译报错。这类异常大多和外部资源交互有关,比如文件读写、网络请求。
常见:IOException、ClassNotFoundException。
2. Unchecked 运行时异常
继承自RuntimeException,编译阶段不会报错,运行时才会触发。这类异常大多是代码书写不规范导致的,理论上可以通过提前判空、逻辑校验规避。
常见:空指针、除数为零、数组下标越界等。
代码示例:运行时异常(算术异常)
public class ExceptionDemo {
public static void main(String[] args) {
int a = 10;
int b = 0;
// 除数为0,运行时抛出ArithmeticException
int result = a / b;
System.out.println(result);
}
}
运行上述代码,程序会直接抛出算术异常并终止。
四、throw 与 throws 关键字
这两个关键字名字相近,但用法、位置、作用完全不同,是高频考点,也是开发常用语法。
1. throws
写在方法声明处,作用是声明当前方法有可能抛出的异常,把异常交给方法的调用者去处理。
- 可以同时声明多个异常,用逗号分隔;
- 主要用于处理受检异常。
代码示例:throws 声明异常
import java.io.FileReader;
import java.io.IOException;
public class ThrowsDemo {
// 声明该方法可能抛出IOException受检异常
public static void readFile() throws IOException {
FileReader fr = new FileReader("test.txt");
fr.close();
}
public static void main(String[] args) throws IOException {
readFile();
}
}
2. throw
写在方法内部,作用是手动主动抛出一个异常对象。
- 一次只能抛出一个异常对象;
- 一般结合条件判断使用,自定义异常场景使用较多。
代码示例:throw 主动抛出异常
public class ThrowDemo {
public static void checkAge(int age) {
if (age < 0) {
// 手动抛出异常对象
throw new IllegalArgumentException("年龄不能为负数!");
}
System.out.println("年龄校验通过");
}
public static void main(String[] args) {
checkAge(-5);
}
}
两者核心区别总结
- 位置:
throws在方法签名后,throw在方法体内; - 内容:
throws后跟异常类名,throw后跟异常实例对象; - 数量:
throws可声明多个异常,throw每次仅抛出一个。
什么时候用 throws,而非 try-catch?
如果一个方法内多处可能抛出异常,逐个编写try-catch会让代码臃肿、可读性变差。此时可以用throws将异常向上传递,统一在调用方集中处理。
五、try-catch-finally 异常捕获结构
这是 Java 最核心的异常处理语法,用来捕获并处理异常。
1. try 块
用来包裹可能出现异常的代码。如果代码正常执行,走完try块;一旦出现异常,立刻终止当前行后续代码,跳转到catch块。
2. catch 块
用来捕获try中抛出的异常,并编写处理逻辑。
- 一个
try可以搭配多个catch,捕获不同类型异常; - 多个 catch 必须遵循:子类异常在前,父类异常在后,否则编译报错。
3. finally 块
可选配置,无论 try 中是否出现异常,finally 代码一定会执行(特殊情况除外)。
核心用途:释放资源,比如关闭文件流、数据库连接、网络连接等。
finally 不会执行的特殊场景
- 代码进入死循环;
- 执行
System.exit(0)终止 JVM。
完整代码示例:try-catch-finally 综合使用
public class TryCatchFinallyDemo {
public static void main(String[] args) {
int num1 = 20;
int num2 = 0;
try {
System.out.println("开始执行运算");
int res = num1 / num2;
System.out.println("运算结果:" + res);
} catch (ArithmeticException e) {
// 捕获算术异常并处理
System.out.println("异常捕获:除数不能为0!");
e.printStackTrace();
} finally {
// 资源释放/收尾代码,必定执行
System.out.println("执行finally代码块,完成收尾操作");
}
System.out.println("程序继续向下运行");
}
}
多 catch 写法示例
public class MultiCatchDemo {
public static void main(String[] args) {
String str = null;
try {
str.length();
} catch (NullPointerException e) {
System.out.println("捕获空指针异常");
} catch (Exception e) {
// 父类异常放最后
System.out.println("捕获通用异常");
}
}
}
六、Java 异常处理最佳实践
结合日常开发经验,分享几点实用的规范,让异常处理更专业:
- 优先捕获具体异常不要直接捕获顶层
Exception,会掩盖真实错误,不利于问题排查。能精准捕获NullPointerException、IOException就不要用Exception。 - 不随意捕获无法处理的异常如果当前业务逻辑没有能力修复该异常,不要强行
catch,使用throws向上抛出,交由上层调用方处理。 - 资源释放交给 finallyIO 流、数据库连接等资源,务必在
finally中关闭,防止资源泄漏。 - 生产环境使用日志记录异常线上项目不要只用
e.printStackTrace()打印控制台,推荐使用日志框架(SLF4J、Logback 等)记录异常堆栈、上下文信息,方便线上排错。
写在最后
异常处理是 Java 基础中非常重要的一环,从基础的概念区分,到try-catch-finally、throw/throws的使用,都是日常编码、面试的高频内容。掌握好异常机制,才能写出稳定、健壮的 Java 程序。



