跳到主要内容
Java 常见异常全面解析:出现场景、错误排查与代码修正实战 | 极客日志
Java java 算法
Java 常见异常全面解析:出现场景、错误排查与代码修正实战 系统讲解了 Java 异常体系结构,涵盖运行时异常与受检异常的详细分析。重点剖析了 NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException 等常见异常的触发场景、堆栈分析及修复方案。同时介绍了 IOException、ClassNotFoundException 的处理技巧,并总结了异常处理的最佳实践,如精准捕获、避免吞噬异常、使用 try-with-resources 及自定义异常增强业务语义等内容,帮助开发者建立系统的异常排查思维。
极客工坊 发布于 2026/3/30 更新于 2026/7/21 57 浏览
引言
本文旨在帮助开发者系统掌握 Java 常见异常的排查与修复能力。通过深入分析异常体系结构、典型运行时异常及受检异常,结合堆栈解读与最佳实践,建立规范的异常处理思维。
一、Java 异常体系回顾
1.1 异常是什么?
异常(Exception) 是程序运行过程中出现的打断正常执行流程的事件。它本质上是一个对象,封装了错误类型、错误描述、方法调用堆栈以及可能的底层原因。
1.2 Java 异常体系结构
java.lang.Object | java.lang.Throwable
---------------------
| |
java.lang.Error java.lang.Exception
-------------------------
| |
RuntimeException 其他 Exception
(运行时异常) (受检异常)
Error :JVM 级别的严重错误,如 OutOfMemoryError、StackOverflowError,程序通常无法处理。
Exception :程序可处理的异常,分为两类:
受检异常(Checked Exception) :编译时必须处理(捕获或声明抛出),如 IOException、SQLException。
运行时异常(RuntimeException) :编译时不强制处理,通常由程序逻辑错误导致,如 NullPointerException、ArrayIndexOutOfBoundsException。
1.3 异常信息解读
一个典型的异常堆栈包含以下要素:
Exception java.lang.IllegalArgumentException: item quantity must be a number at io.jzheaux.pluralsight.DeliController.orderSandwich (DeliController.java:45 ) // … Caused by java.lang.NumberFormatException: For input string : " 3" at NumberFormatException.forInputString (NumberFormatException.java:67 ) at Integer .parseInt (Integer .java:647 ) ...
异常类型 :IllegalArgumentException
异常消息 :item quantity must be a number
堆栈轨迹 :从 main 开始到异常发生处的调用链
Caused by :底层根本原因,通常是排查的关键入口排查技巧 :遇到复杂异常时,不要只看第一行,要顺着堆栈往下找,尤其是'Caused by'部分,那里往往藏着真正的原因。
二、常见运行时异常深度剖析 运行时异常(RuntimeException)是 Java 程序中最常见的异常类型,它们通常由代码逻辑错误引起。下面我们将逐个剖析最常见的运行时异常。
2.1 NullPointerException(空指针异常)
现象描述 当应用程序试图在需要对象的地方使用 null 引用时,抛出此异常。这是 Java 中最著名的异常,占据了异常总数的很大比例。
出现场景 String text = null ;
int length = text.length();
Boolean willVote = null ;
if (willVote) {
System.out.println("可以投票" );
}
void parseDocument (Document doc) {
doc.getElements();
}
String lookupElement (Document doc) {
Element element = doc.findElement("span" );
return element.getValue();
}
Person[] people = new Person [5 ];
people[0 ].getName();
堆栈分析示例 Exception in thread "main" java.lang.NullPointerException
at com.example.UserService.getUserAge (UserService.java :25 )
at com.example.UserController.main (UserController.java :12 )
从堆栈可以看出,UserService.java的第 25 行调用了某个 null 对象的方法。
排查方法流程图 方法参数 → 方法返回值 → 未初始化变量 → 数组元素 → 发现 NullPointerException → 定位堆栈中第一个出现自己代码的行号 → 检查该行代码有哪些对象可能为 null → 对象来源是什么? → 检查调用方是否传入 null / 检查被调用方法是否可能返回 null / 检查变量是否已正确初始化 / 检查数组元素是否已赋值 → 修复调用方或添加空值校验
代码修正与预防
void parseDocument (Document doc) {
doc.getElements();
}
void parseDocument (@NonNull Document doc) {
if (doc == null ) {
throw new IllegalArgumentException ("doc cannot be null" );
}
doc.getElements();
}
String lookupElement (Document doc) {
Element element = doc.findElement("span" );
return element.getValue();
}
@Nullable String lookupElement (Document doc) {
Element element = doc.findElement("span" );
if (element == null ) {
return null ;
}
return element.getValue();
}
修正方案三:使用 Optional(Java 8+)
public Optional<String> lookupElement (Document doc) {
return Optional.ofNullable(doc.findElement("span" )).map(Element::getValue);
}
Person[] people = new Person [5 ];
for (int i = 0 ; i < people.length; i++) {
people[i] = new Person ();
}
明确空值来源 :是无效值(上游问题)还是有效值(可接受 null)
使用@NonNull 和@Nullable 注解 ,让 IDE 帮助检查
遵循"尽早失败"原则 :在方法入口处就进行参数校验
谨慎处理返回值 :明确方法是否可能返回 null,并在文档中说明
2.2 ArrayIndexOutOfBoundsException(数组下标越界异常)
现象描述 当试图使用非法索引访问数组元素时抛出,非法索引包括负数、0 到数组长度减 1 范围外的值。
出现场景 int [] numbers = {1 , 2 , 3 };
int value = numbers[3 ];
int [] scores = {85 , 90 , 78 , 92 };
for (int i = 0 ; i <= scores.length; i++) {
System.out.println(scores[i]);
}
int [] data = new int [10 ];
int index = -1 ;
data[index] = 100 ;
堆栈分析示例 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at com.example.ArrayDemo.processArray (ArrayDemo.java :15 )
at com.example.ArrayDemo.main (ArrayDemo.java :8 )
异常信息直接告诉我们:试图访问索引 5,但数组长度只有 5(有效索引 0-4)。
排查方法 直接常量 → 循环变量 → 计算结果 → 发现 ArrayIndexOutOfBoundsException → 定位堆栈中的代码行 → 检查该行代码的数组访问表达式 → 索引值是如何计算的? → 检查常量是否在合法范围内 / 检查循环条件边界 / 检查计算逻辑是否有误 → 修正索引值
代码修正与预防
for (int i = 0 ; i <= scores.length; i++) {
System.out.println(scores[i]);
}
for (int i = 0 ; i < scores.length; i++) {
System.out.println(scores[i]);
}
for (int score : scores) {
System.out.println(score);
}
public int getElement (int [] array, int index) {
if (array == null ) {
throw new IllegalArgumentException ("array cannot be null" );
}
if (index < 0 || index >= array.length) {
throw new IndexOutOfBoundsException ("Index " + index + " out of bounds for length " + array.length);
}
return array[index];
}
优先使用增强 for 循环 处理数组遍历
使用 Arrays 工具类 的方法进行数组操作
动态计算索引时 ,添加边界检查
考虑使用 ArrayList 等集合类,它们提供了更安全的 get() 方法(也会抛出越界异常,但信息更明确)
2.3 ClassCastException(类型转换异常)
现象描述 当试图将一个对象强制转换为它不是实例的子类时抛出。这是使用继承和多态时的常见问题。
出现场景 Object obj = new Object ();
Integer num = (Integer) obj;
List list = new ArrayList ();
list.add("Hello" );
list.add(123 );
String first = (String) list.get(0 );
String second = (String) list.get(1 );
Animal animal = new Dog ();
Cat cat = (Cat) animal;
堆栈分析示例 Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String
at com.example.GenericDemo.processList(GenericDemo.java:22 )
at com.example.GenericDemo.main(GenericDemo.java:15 )
异常信息明确告诉我们:试图将 Integer 转换为 String,类型不兼容。
排查方法 集合 → 方法返回值 → 从外部系统获取 → 发现 ClassCastException → 定位堆栈中的转换代码行 → 检查被转换对象的实际类型 → 对象来源是什么? → 检查集合中元素类型是否一致 / 检查返回类型的实际实现 / 检查序列化/反序列化过程 → 使用泛型或 instanceof 检查
代码修正与预防
List list = new ArrayList ();
list.add("Hello" );
String s = (String) list.get(0 );
List<String> list = new ArrayList <>();
list.add("Hello" );
String s = list.get(0 );
Object obj = getSomeObject();
if (obj instanceof String) {
String str = (String) obj;
} else if (obj instanceof Integer) {
Integer num = (Integer) obj;
}
修正方案三:Java 16+ 的 Pattern Matching for instanceof
Object obj = getSomeObject();
if (obj instanceof String str) {
System.out.println(str.length());
} else if (obj instanceof Integer num) {
System.out.println(num + 10 );
} else {
}
始终使用泛型 确保集合类型安全
在向下转型前使用 instanceof 检查
遵循里氏替换原则 ,避免不必要的向下转型
考虑使用多态 ,而不是频繁的类型转换
2.4 ArithmeticException(算术异常)
现象描述
出现场景 注意 :浮点数除零不会抛出异常,会返回 Infinity 或 NaN
double result = 10.0 / 0.0 ;
堆栈分析示例 Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.example.Calculator.divide (Calculator.java :10 )
at com.example.Calculator.main (Calculator.java :5 )
排查方法 直接常量 → 变量 → 方法返回值 → 发现 ArithmeticException → 定位堆栈中的除法/取模代码 → 检查分母/右操作数的值 → 分母来源是什么? → 修改常量为非零值 / 检查变量赋值逻辑 / 检查返回值的范围 → 添加除零检查
代码修正与预防 public int divide (int a, int b) {
if (b == 0 ) {
throw new IllegalArgumentException ("除数不能为 0" );
}
return a / b;
}
修正方案二:使用 Optional 处理可能为 0 的情况
public Optional<Integer> safeDivide (int a, int b) {
if (b == 0 ) {
return Optional.empty();
}
return Optional.of(a / b);
}
double result = 10.0 / 0.0 ;
if (Double.isInfinite(result)) {
}
在进行除法或取模前,始终检查除数是否为 0
考虑使用 BigDecimal 进行精确计算,它提供了更好的异常处理
从用户输入获取除数时 ,必须进行验证
三、其他运行时异常与受检异常
3.1 NumberFormatException(数字格式异常)
现象描述 当尝试将字符串转换为数字类型,但字符串格式不合法时抛出。
出现场景 int num = Integer.parseInt("123abc" );
int num = Integer.parseInt(" 123 " );
int num = Integer.parseInt("2147483648" );
int num = Integer.parseInt("" );
Integer.parseInt(null );
堆栈分析示例 Exception in thread "main" java.lang.NumberFormatException: For input string : " 123 "
at java.base/java.lang.NumberFormatException.forInputString (NumberFormatException.java :67 )
at java.base/java.lang.Integer.parseInt (Integer.java :654 )
at java.base/java.lang.Integer.parseInt (Integer.java :786 )
at com.example.UserInput.processAge (UserInput.java :12 )
排查方法 graph TD
A[开始] --> B{输入是否为 null?}
B -- 是 --> C[抛出 NullPointerException]
B -- 否 --> D{去除前后空格}
D --> E{是否为空?}
E -- 是 --> F[抛出 NumberFormatException]
E -- 否 --> G{匹配正则 \d+?}
G -- 否 --> H[抛出 NumberFormatException]
G -- 是 --> I[成功解析]
代码修正与预防
String input = " 123 " ;
int value = Integer.parseInt(input);
String input = " 123 " ;
input = input.trim();
if (!input.isEmpty()) {
try {
int value = Integer.parseInt(input);
} catch (NumberFormatException e) {
}
}
public int parsePostalCode (String input) {
if (input == null || !input.matches("\\d{5}" )) {
throw new IllegalArgumentException ("邮政编码必须是 5 位数字" );
}
return Integer.parseInt(input);
}
修正方案三:使用 Apache Commons Lang 的 NumberUtils
import org.apache.commons.lang3.math.NumberUtils;
String input = "123" ;
int value = NumberUtils.toInt(input, 0 );
修正方案四:Java 8+ 的 Optional + 异常处理
public Optional<Integer> tryParseInt (String input) {
try {
return Optional.of(Integer.parseInt(input.trim()));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
始终对输入进行清洗 (trim、去除非数字字符)
解析前验证格式 ,特别是来自外部系统的数据
考虑使用专门的验证框架 如 Hibernate Validator
使用 try-catch 包围解析代码 ,优雅处理异常
3.2 IllegalArgumentException(非法参数异常)
现象描述 当向方法传递了不合法或不适当的参数时抛出。这通常表示调用者的责任。
出现场景 public void setAge (int age) {
if (age < 0 || age > 150 ) {
throw new IllegalArgumentException ("年龄必须在 0-150 之间" );
}
this .age = age;
}
public void setEmail (String email) {
if (email == null || !email.contains("@" )) {
throw new IllegalArgumentException ("邮箱格式不正确" );
}
this .email = email;
}
public void processData (@NonNull Data data) {
if (data == null ) {
throw new IllegalArgumentException ("data cannot be null" );
}
}
排查方法
查看异常消息 ,通常会说明参数需要满足什么条件
检查调用代码 ,确认传入的参数值
验证参数来源 ,判断是输入错误还是上游数据问题
代码修正
public void registerUser (String username, String email, int age) {
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException ("用户名不能为空" );
}
if (email == null || !email.matches("^[A-Za-z0-9+_.-]+@(.+)$" )) {
throw new IllegalArgumentException ("邮箱格式不正确" );
}
if (age < 0 || age > 150 ) {
throw new IllegalArgumentException ("年龄无效" );
}
}
3.3 IllegalStateException(非法状态异常)
现象描述 当方法在非法或不适当的时间被调用时抛出。通常表示被调用者的状态不适合执行请求的操作。
出现场景 public class ConnectionPool {
private boolean initialized = false ;
public void connect () {
if (!initialized) {
throw new IllegalStateException ("连接池未初始化" );
}
}
}
List<String> list = Arrays.asList("A" , "B" );
Iterator<String> it = list.iterator();
it.next();
it.next();
it.next();
排查方法
阅读异常消息 ,了解当前对象应该处于什么状态
检查对象初始化或配置代码 ,确保在调用前已正确设置
检查操作顺序 ,确认是否按正确步骤调用
代码修正 public class FileProcessor {
private boolean opened = false ;
public void open () {
opened = true ;
}
public void readData () {
if (!opened) {
throw new IllegalStateException ("必须先调用 open() 方法打开文件" );
}
}
}
3.4 IOException(输入输出异常)
现象描述 当输入输出操作失败或中断时抛出。这是最典型的受检异常,处理文件、网络、流操作时经常遇到。
出现场景 场景一:文件不存在(FileNotFoundException)
FileReader fr = new FileReader ("nonexistent.txt" );
InputStream in = socket.getInputStream();
int data = in.read();
FileOutputStream fos = new FileOutputStream ("largefile.bin" );
byte [] data = new byte [1024 ];
fos.write(data);
堆栈分析示例 java.io .FileNotFoundException: nonexistent.txt (系统找不到指定的文件)
at java.base/java.io .FileInputStream.open0(Native Method)
at java.base/java.io .FileInputStream.open (FileInputStream.java:219 )
at java.base/java.io .FileInputStream.<init>(FileInputStream.java:157 )
at com.example.FileReaderDemo.main(FileReaderDemo.java:8 )
排查方法 FileNotFoundException → EOFException → SocketException → 其他 IO 错误 → 发现 IOException → 查看异常消息中的具体原因 → 原因类型? → 检查文件路径和存在性 / 检查是否提前到达文件末尾 / 检查网络连接状态 / 检查磁盘空间、权限等 → 修正路径或创建文件
代码修正与预防 修正方案一:使用 try-with-resources 确保资源关闭
public String readFile (String path) throws IOException {
FileReader fr = new FileReader (path);
BufferedReader br = new BufferedReader (fr);
return br.readLine();
}
public String readFile (String path) throws IOException {
try (FileReader fr = new FileReader (path);
BufferedReader br = new BufferedReader (fr)) {
return br.readLine();
}
}
public void processFile (String path) {
File file = new File (path);
if (!file.exists()) {
System.err.println("文件不存在:" + path);
return ;
}
try (BufferedReader br = new BufferedReader (new FileReader (file))) {
} catch (IOException e) {
System.err.println("读取文件时发生错误:" + e.getMessage());
e.printStackTrace();
}
}
public void copyFile (String src, String dest) {
try (FileInputStream in = new FileInputStream (src);
FileOutputStream out = new FileOutputStream (dest)) {
byte [] buffer = new byte [1024 ];
int length;
while ((length = in.read(buffer)) > 0 ) {
out.write(buffer, 0 , length);
}
} catch (FileNotFoundException e) {
System.err.println("源文件不存在或目标目录无法写入:" + e.getMessage());
} catch (IOException e) {
System.err.println("复制过程中发生 IO 错误:" + e.getMessage());
}
}
始终使用 try-with-resources 或确保 finally 中关闭资源
操作前检查文件和目录状态
为 IO 操作提供有意义的错误消息
考虑重试机制 ,特别是网络相关的 IO 操作
3.5 ClassNotFoundException(类未找到异常)
现象描述 当应用程序试图通过字符串名加载类,但在类路径中找不到该类的定义时抛出。
出现场景 Class.forName("com.mysql.jdbc.Driver" );
ClassLoader.getSystemClassLoader().loadClass("com.example.MissingClass" );
Object obj = Class.forName("com.example.DynamicClass" ).newInstance();
堆栈分析示例 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
排查方法 是 → 否 → 发现 ClassNotFoundException → 查看缺少的类名 → 确认该类属于哪个库/JAR → 该类是否应该存在? → 检查类路径配置 → 检查类名拼写或版本兼容性 → 添加缺失的 JAR 到类路径
代码修正与预防
对于 Maven 项目:检查 pom.xml 中的依赖
对于普通项目:确认 JAR 文件在 classpath 下
try {
Class.forName("com.mysql.jdbc.Driver" );
} catch (ClassNotFoundException e) {
throw new RuntimeException ("MySQL 驱动未找到,请检查是否添加了 mysql-connector-java 依赖" , e);
}
修正方案三:使用 ServiceLoader 模式(Java 6+)
ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
for (Driver driver : drivers) {
}
四、综合实战与最佳实践
4.1 复杂异常排查案例
案例:银行转账系统中的异常链 public class BankingService {
public void transfer (String fromAccount, String toAccount, double amount) throws BusinessException {
try {
Account from = accountRepository.findByNumber(fromAccount);
Account to = accountRepository.findByNumber(toAccount);
if (from == null || to == null ) {
throw new IllegalArgumentException ("账户不存在" );
}
from.withdraw(amount);
to.deposit(amount);
transactionLog.log(fromAccount, toAccount, amount);
} catch (IllegalArgumentException e) {
throw new BusinessException ("转账参数错误" , e);
} catch (InsufficientBalanceException e) {
throw new BusinessException ("余额不足" , e);
} catch (Exception e) {
throw new BusinessException ("转账失败,请稍后重试" , e);
}
}
}
异常排查思路 com .example .BusinessException : 转账失败,请稍后重试
at com .example .BankingService .transfer (BankingService.java :45 )
at com .example .BankingController .main (BankingController.java :18 )
Caused by : java .sql .SQLException : Connection timed out
at com .mysql .jdbc .ConnectionImpl .createNewIO (ConnectionImpl.java :2189 )
at com .mysql .jdbc .ConnectionImpl .<init >(ConnectionImpl.java :795 )
at com .mysql .jdbc .NonRegisteringDriver .connect (NonRegisteringDriver.java :329 )
at java .sql .DriverManager .getConnection (DriverManager.java :664 )
at com .example .AccountRepository .findByNumber (AccountRepository.java :22 )
... 5 more
看顶层异常 :BusinessException,但消息太泛化,请稍后重试 没有实质信息
看 Caused by :SQLException: Connection timed out,这才是真正原因
追溯源头 :AccountRepository.java:22 处的数据库连接超时
根本原因 :数据库连接失败
检查数据库服务是否运行
检查网络连接
检查数据库连接池配置
添加重试机制
教训 :包装异常时不要丢失原始信息,提供具体的错误消息有助于排查。
4.2 异常处理最佳实践总结
4.2.1 捕获特定异常,而不是通用异常
try {
} catch (Exception e) {
}
try {
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
4.2.2 避免空的 catch 块
try {
riskyOperation();
} catch (Exception e) {
}
try {
riskyOperation();
} catch (Exception e) {
logger.error("操作失败" , e);
throw e;
}
4.2.3 使用 try-with-resources 自动关闭资源
FileInputStream fis = null ;
try {
fis = new FileInputStream ("file.txt" );
} finally {
if (fis != null ) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try (FileInputStream fis = new FileInputStream ("file.txt" )) {
}
4.2.4 使用自定义异常增强业务语义
public class InsufficientBalanceException extends Exception {
private double currentBalance;
private double requiredAmount;
public InsufficientBalanceException (double current, double required) {
super (String.format("余额不足:当前余额%.2f,需要%.2f" , current, required));
this .currentBalance = current;
this .requiredAmount = required;
}
}
public void withdraw (double amount) throws InsufficientBalanceException {
if (balance < amount) {
throw new InsufficientBalanceException (balance, amount);
}
balance -= amount;
}
4.2.5 方法重写时遵守异常声明规则
子类方法可以抛出与父类相同的异常、子类异常,或不抛出异常
子类方法不能抛出比父类更宽泛的受检异常
class Parent {
public void process () throws IOException {}
}
class Child extends Parent {
@Override
public void process () throws FileNotFoundException {}
}
4.2.6 记录异常时包含上下文信息 try {
processOrder(orderId, userId);
} catch (OrderException e) {
logger.error("处理订单失败:orderId={}, userId={}" , orderId, userId, e);
throw e;
}
4.2.7 不要用异常控制正常的程序流程
try {
Integer.parseInt(userInput);
} catch (NumberFormatException e) {
}
if (userInput.matches("\\d+" )) {
int value = Integer.parseInt(userInput);
} else {
}
4.2.8 异常处理的黄金法则总结 原则 说明 精准捕获 捕获具体的异常类型,而不是笼统的 Exception 绝不吞噬 空的 catch 块是万恶之源,至少要记录日志 及时释放 使用 try-with-resources 或 finally 确保资源释放 保留原始异常 包装异常时要把原异常作为 cause 传入 提供上下文 异常消息要包含有助于排查的信息 区分异常类型 可恢复用受检异常,程序错误用运行时异常 文档化 用 javadoc 的@throws 说明方法可能抛出的异常
4.3 Java 7+ 多异常捕获 从 Java 7 开始,可以使用 | 在一个 catch 块中捕获多个异常类型,减少代码重复:
try {
} catch (IOException | SQLException e) {
logger.error("数据访问错误" , e);
throw e;
}
注意 :多异常捕获时,catch 参数隐式为 final,不能修改。
4.4 异常处理与事务管理 在企业级应用中,异常处理与事务管理密切相关。通常:
运行时异常 触发事务回滚
受检异常 不自动触发事务回滚(在 Spring 中可通过 rollbackFor 配置)
@Service
public class AccountService {
@Transactional(rollbackFor = {BusinessException.class, RuntimeException.class})
public void transferMoney (String from, String to, double amount) throws BusinessException {
try {
} catch (InsufficientBalanceException e) {
throw new BusinessException ("转账失败" , e);
}
}
}
五、总结
知识体系回顾
异常基础 :体系结构、受检与非受检异常、异常信息解读
运行时异常 :
NullPointerException:空引用访问 → 前置检查、Optional
ArrayIndexOutOfBoundsException:数组越界 → 边界检查、增强 for 循环
ClassCastException:类型转换错误 → instanceof 检查、泛型
ArithmeticException:算术异常 → 除零检查
NumberFormatException:数字格式错误 → 输入清洗、预验证
IllegalArgumentException/IllegalStateException:参数/状态错误 → 前置校验
受检异常 :
IOException及其子类 → try-with-resources、文件存在性检查
ClassNotFoundException → 检查类路径、依赖管理
排查方法 :堆栈分析、Caused by 追踪、异常链理解
最佳实践 :精准捕获、避免吞噬、及时释放、保留上下文等 8 大原则
异常排查思维导图 graph TD
A[遇到异常] --> B{1. 看类型:是什么异常?}
B --> C{2. 看消息:说了什么?}
C --> D{3. 看堆栈:第一行在哪?}
D --> E{4. 看原因:有 Caused by?}
E --> F{5. 想来源:值从哪来?}
F --> G{6. 想方案:怎么修复?}
G --> H[结束]
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online