
🌸你好呀!我是断弦承露
🌟感谢陪伴~ 小白博主在线求友
🌿 跟着小白学/Java/软件设计/鸿蒙开发/芯片开发
📖专栏汇总:
《软件设计师》专栏 | 《Java》专栏 | 《 RISC-V 处理器实战》专栏 | 《Flutter鸿蒙实战》专栏 | 《React Native开发》专栏 ------|CSDN|------

文章目录
- [Java异常体系与处理全解:核心原理、实战用法、避坑指南 | 2026 JDK21 最新版](#Java异常体系与处理全解:核心原理、实战用法、避坑指南 | 2026 JDK21 最新版)
-
- [🧠 文章核心思维导图](#🧠 文章核心思维导图)
- [📖 1. 异常的核心概念](#📖 1. 异常的核心概念)
-
- [1.1 什么是异常 🎯](#1.1 什么是异常 🎯)
- [1.2 异常处理的核心价值 ✨](#1.2 异常处理的核心价值 ✨)
- [🏗️ 2. Java异常的完整体系结构](#🏗️ 2. Java异常的完整体系结构)
-
- [2.1 顶层父类:java.lang.Throwable 📦](#2.1 顶层父类:java.lang.Throwable 📦)
- [2.2 Error:系统级严重错误 ⚠️](#2.2 Error:系统级严重错误 ⚠️)
- [2.3 Exception:程序级异常 🛠️](#2.3 Exception:程序级异常 🛠️)
-
- [2.3.1 运行时异常(非受检异常)](#2.3.1 运行时异常(非受检异常))
- [2.3.2 编译时异常(受检异常)](#2.3.2 编译时异常(受检异常))
- [✍️ 3. Java异常处理的核心语法](#✍️ 3. Java异常处理的核心语法)
-
- [3.1 try-catch:异常捕获核心结构 🎣](#3.1 try-catch:异常捕获核心结构 🎣)
- [3.2 finally:必执行代码块 🔒](#3.2 finally:必执行代码块 🔒)
- [3.3 try-with-resources:自动资源释放 🚮](#3.3 try-with-resources:自动资源释放 🚮)
- [3.4 throws:异常声明 📢](#3.4 throws:异常声明 📢)
- [3.5 throw:手动抛出异常 🚀](#3.5 throw:手动抛出异常 🚀)
- [📏 4. 异常处理的行业最佳实践](#📏 4. 异常处理的行业最佳实践)
- [🚨 5. 新手高频报错与解决方案](#🚨 5. 新手高频报错与解决方案)
- [❓ 6. 常见问题FAQ](#❓ 6. 常见问题FAQ)
- [💻 7. 完整实战案例](#💻 7. 完整实战案例)
- [🔗 权威参考链接](#🔗 权威参考链接)
Java异常体系与处理全解:核心原理、实战用法、避坑指南 | 2026 JDK21 最新版

📝 摘要
本文面向Java零基础开发者,系统拆解Java异常的核心概念、完整体系结构、5大核心处理语法,结合JDK21最新LTS版本特性,提供代码示例、新手高频报错解决方案、行业通用最佳实践与常见问题FAQ。帮助开发者快速掌握Java异常处理核心能力,写出高健壮性的工业级Java程序。
🧠 文章核心思维导图
Java异常体系全解
核心概念
异常体系结构
异常处理核心语法
最佳实践与规范
新手高频报错与解决方案
常见问题FAQ
完整实战案例
异常的定义
异常与语法/逻辑错误的区别
顶层父类Throwable
Error系统级错误
Exception程序级异常
运行时异常 非受检异常
编译时异常 受检异常
try-catch异常捕获
finally代码块
try-with-resources资源释放
throws异常声明
throw手动抛异常
📖 1. 异常的核心概念
1.1 什么是异常 🎯
Java中,异常 指程序运行过程中,打断正常执行流程的非正常情况。它是Java内置的错误处理机制,核心作用是将正常业务逻辑与错误处理逻辑分离,避免程序直接崩溃,提升代码的健壮性与可维护性。
常见的异常触发场景包括:
- 试图打开的文件不存在
- 网络连接意外中断
- 数组访问下标超出合法范围
- 要加载的类在运行时找不到
- 对null对象调用方法或访问属性
注意:语法错误、逻辑错误不属于异常。语法错误在编译期就会被编译器拦截,无法生成class字节码文件;逻辑错误是程序正常运行但输出结果不符合预期,不会抛出异常。
1.2 异常处理的核心价值 ✨
- 避免程序非预期终止,保障核心业务的可用性
- 分离正常业务逻辑与错误处理逻辑,代码结构更清晰
- 提供标准化的错误信息与堆栈追踪,快速定位问题根因
- 支持异常向上传递,实现项目级统一的异常处理逻辑
🏗️ 2. Java异常的完整体系结构
Java异常的顶层父类是java.lang.Throwable,只有该类及其子类的对象,才能被Java异常处理机制处理(即可以被throw关键字抛出、被catch代码块捕获)。
Throwable分为两大核心分支:Error和Exception,完整体系如下:
java.lang.Throwable
Error 系统级错误
Exception 程序级异常
VirtualMachineError
AWTError
StackOverflowError
OutOfMemoryError OOM
RuntimeException 运行时异常
编译时异常 受检异常
NullPointerException
ArithmeticException
ArrayIndexOutOfBoundsException
ClassCastException
NumberFormatException
IOException
FileNotFoundException
ClassNotFoundException
SQLException
2.1 顶层父类:java.lang.Throwable 📦
Throwable是所有异常类的根父类,提供了异常处理的核心方法,常用方法如下:
| 方法名 | 核心作用 |
|---|---|
printStackTrace() |
打印异常的完整堆栈追踪信息,包括异常类型、描述、触发位置,是问题排查最核心的方法 |
getMessage() |
获取异常的详细描述文本 |
getCause() |
获取异常的根本原因,用于异常链的全链路追踪 |
fillInStackTrace() |
填充当前线程的堆栈信息到异常对象中,多用于自定义异常时重置堆栈追踪 |
2.2 Error:系统级严重错误 ⚠️
Error是JVM层面的致命问题,通常无法通过程序恢复,语法上虽可被捕获,但行业规范不建议主动处理。这类错误发生时往往意味着JVM运行环境出现不可逆的问题,通常会导致JVM进程异常退出,仅能通过代码优化、JVM参数调优提前规避。
常见的Error示例:
StackOverflowError:栈溢出,通常由无限递归、过深的方法调用导致OutOfMemoryError:OOM内存溢出,JVM可用内存耗尽,无法为新对象分配内存空间
可运行示例代码:
java
/**
* 演示StackOverflowError栈溢出错误
* 无限递归调用会导致方法栈超出JVM分配的最大深度,触发该错误
*/
public class StackOverflowErrorDemo {
public static void main(String[] args) {
// 触发无限递归,复现栈溢出错误
infiniteRecursion();
}
/**
* 无终止条件的递归方法
*/
public static void infiniteRecursion() {
infiniteRecursion();
}
}
2.3 Exception:程序级异常 🛠️
Exception是程序运行过程中出现的一般性问题,可以通过代码进行捕获和处理,是日常开发中异常处理的核心对象。
Exception分为两大类:运行时异常(非受检异常 Unchecked Exception) 和编译时异常(受检异常 Checked Exception)。
2.3.1 运行时异常(非受检异常)
java.lang.RuntimeException及其所有子类,都属于运行时异常。这类异常编译器不强制要求处理,编译期可正常通过,仅在程序运行时触发,大多由代码逻辑不严谨导致,开发者应提前预判和规避。
常见的运行时异常及触发场景:
| 异常类名 | 触发场景 |
|---|---|
NullPointerException 空指针异常 |
对null对象调用方法、访问属性,是开发中最高发的异常 |
ArithmeticException 算术运算异常 |
整数除法中除数为0、非法的数学运算 |
ArrayIndexOutOfBoundsException 数组下标越界异常 |
访问的数组下标超出了[0, 数组长度-1]的合法范围 |
ClassCastException 类型转换异常 |
对不兼容的两个类型进行强制类型转换 |
NumberFormatException 数字格式异常 |
将非数字格式的字符串转换为数字类型 |
IllegalArgumentException 非法参数异常 |
方法传入的参数不符合业务规则要求 |
可运行示例代码(数组越界异常):
java
/**
* 演示ArrayIndexOutOfBoundsException数组下标越界异常
* 变量命名语义化,边界问题清晰可复现
*/
public class ArrayIndexExceptionDemo {
public static void main(String[] args) {
// greetingArray:存储问候语的字符串数组,数组长度为3,合法下标范围是0、1、2
String[] greetingArray = {"Hello World!", "Hello!", "HELLO WORLD!!"};
// arrayIndex:数组遍历的下标变量,初始值为0,对应数组第一个元素
int arrayIndex = 0;
// 循环条件错误:arrayIndex < 4 会让下标遍历到3,超出数组合法范围
while (arrayIndex < 4) {
System.out.println(greetingArray[arrayIndex]);
arrayIndex++;
}
// 异常触发后,该行代码不会执行,程序直接终止
System.out.println("程序正常结束");
}
}
2.3.2 编译时异常(受检异常)
除RuntimeException之外的所有Exception子类,都属于编译时异常。这类异常编译器会强制检查,必须在代码中进行处理(捕获或声明),否则无法通过编译,通常由外部环境因素导致,比如文件不存在、网络连接失败等。
常见的编译时异常及触发场景:
| 异常类名 | 触发场景 |
|---|---|
IOException 输入输出异常 |
文件、网络流操作过程中发生的通用IO错误 |
FileNotFoundException 文件不存在异常 |
试图操作的文件路径不存在,或无访问权限 |
ClassNotFoundException 类找不到异常 |
试图加载的类不存在,通常由类名拼写错误、缺少依赖包导致 |
SQLException 数据库操作异常 |
执行SQL语句、操作数据库时发生的执行错误 |
EOFException 文件末尾异常 |
读取文件时意外到达文件末尾,无法读取到预期内容 |
✍️ 3. Java异常处理的核心语法
Java异常处理有5个核心关键字:try、catch、finally、throws、throw,同时提供了try-with-resources语法实现资源的自动释放。
3.1 try-catch:异常捕获核心结构 🎣
try-catch是异常处理的核心结构,用于捕获并处理代码中可能抛出的异常,保障程序不会直接终止。
通用语法模板
java
try {
// 可能抛出异常的业务代码
} catch (异常类型1 异常变量名) {
// 异常类型1的专属处理逻辑
} catch (异常类型2 异常变量名) {
// 异常类型2的专属处理逻辑
}
执行流程图
无异常
有异常
匹配成功
匹配失败
进入try代码块
是否发生异常?
执行完try块全部代码
是否有匹配的catch块?
执行对应catch块的处理逻辑
异常向上抛出,程序终止
执行后续业务代码
可运行示例代码
java
/**
* try-catch异常捕获示例
* 捕获数组越界异常,处理后程序可继续正常执行
*/
public class TryCatchDemo {
public static void main(String[] args) {
String[] greetingArray = {"Hello World!", "Hello!", "HELLO WORLD!!"};
int arrayIndex = 0;
try {
// 可能抛出异常的业务代码
while (arrayIndex < 4) {
System.out.println(greetingArray[arrayIndex]);
arrayIndex++;
}
System.out.println("try块代码执行完毕");
} catch (ArrayIndexOutOfBoundsException e) {
// 异常触发后的处理逻辑
System.err.println("捕获到数组越界异常:" + e.getMessage());
// 打印完整堆栈信息,便于问题排查
e.printStackTrace();
}
// 异常处理完成后,该行代码会正常执行
System.out.println("程序正常结束,未被异常终止");
}
}
关键注意事项(新手必看)
- 多catch块的顺序要求:子类异常必须写在前面,父类异常写在后面。如果父类异常在前,子类异常的catch块永远无法执行,编译器会直接报错。
- 禁止空catch块:catch块中不能只捕获异常不做任何处理,会导致异常被"吞掉",无法定位问题根因。
- 禁止捕获
Throwable:会捕获到Error等系统级致命错误,干扰JVM的错误退出机制。
3.2 finally:必执行代码块 🔒
finally代码块的核心特性是:无论try块中是否发生异常、catch块是否执行,finally块中的代码一定会执行 ,唯一例外是在try/catch块中执行了System.exit(0)强制退出JVM。
核心使用场景
释放系统资源,比如关闭文件流、数据库连接、网络连接等,避免资源泄漏。
通用语法模板
java
try {
// 可能抛出异常的业务代码
} catch (异常类型 异常变量名) {
// 异常处理逻辑
} finally {
// 无论是否发生异常,都会执行的代码
}
关键避坑
禁止在finally块中编写return语句,会覆盖try块中的return结果,导致业务逻辑混乱。
3.3 try-with-resources:自动资源释放 🚮
try-with-resources是JDK7及以上版本提供的语法,JDK21完全兼容并优化,是目前资源释放的行业最佳实践。它可以自动关闭实现了AutoCloseable接口的资源对象,无需手动在finally中关闭,从根本上避免资源泄漏问题。
JDK9+增强(JDK21全兼容):支持在try代码块外声明final或等效final的资源对象,放入try-with-resources中自动关闭。
通用语法模板
java
// 括号内声明实现了AutoCloseable接口的资源对象
try (资源类型 资源变量名 = new 资源实现类()) {
// 业务代码
} catch (异常类型 异常变量名) {
// 异常处理逻辑
}
可运行示例代码
java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
* try-with-resources自动资源释放示例
* 自动关闭文件流,无需手动调用close()方法
*/
public class TryWithResourcesDemo {
public static void main(String[] args) {
// filePath:要读取的文件路径字符串
String filePath = "test.txt";
// 声明BufferedReader资源,实现了AutoCloseable接口,会自动关闭
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
String lineContent;
// 循环读取文件的每一行内容
while ((lineContent = bufferedReader.readLine()) != null) {
System.out.println(lineContent);
}
} catch (IOException e) {
// 捕获文件操作过程中的所有IO异常
System.err.println("文件读取失败:" + e.getMessage());
e.printStackTrace();
}
}
}
3.4 throws:异常声明 📢
throws用于在方法声明上,标记该方法可能抛出的异常,将异常的处理责任交给方法的调用方。
通用语法模板
java
// 格式:修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2
public void readFile(String filePath) throws FileNotFoundException, IOException {
// 方法体业务代码
}
关键规则
- 编译时异常必须处理:要么在方法内部用try-catch捕获,要么用throws声明,交给调用方处理。
- 运行时异常可以不声明:编译器不强制要求,但如果有明确的异常风险,建议声明告知调用方。
- 方法重写时,子类方法声明的异常不能超出父类方法声明的异常范围。
3.5 throw:手动抛出异常 🚀
throw用于在代码中手动抛出一个异常对象,通常用于业务逻辑不符合预期的场景,比如参数非法、业务规则不满足等。
通用语法模板
java
throw new 异常类型("异常描述信息");
可运行示例代码
java
/**
* throw手动抛出异常示例
* 业务参数非法时,手动抛出异常终止流程
*/
public class ThrowDemo {
public static void main(String[] args) {
// 调用方法,传入非法的年龄参数
checkUserAge(-5);
}
/**
* 校验用户年龄是否合法
* @param userAge 用户年龄,必须大于等于0
*/
public static void checkUserAge(int userAge) {
if (userAge < 0) {
// 年龄非法,手动抛出非法参数异常
throw new IllegalArgumentException("用户年龄不能为负数,输入的年龄为:" + userAge);
}
System.out.println("年龄校验通过,年龄为:" + userAge);
}
}
📏 4. 异常处理的行业最佳实践
本文参考[阿里巴巴Java开发手册],结合2026年Java开发通用标准与JDK21特性,整理以下最佳实践:
- 异常必须打印完整堆栈信息 :禁止只捕获异常不打印堆栈,或仅打印
e.getMessage(),完整的堆栈信息是定位问题的核心依据。 - 不要用异常控制业务流程:异常是用于处理非正常情况的,不要用try-catch代替正常的if-else条件判断,会严重影响程序性能和代码可读性。
- 捕获具体的异常类型 :禁止直接捕获
Exception,要捕获具体的子类异常,明确处理的异常类型,避免捕获到预期之外的运行时异常。 - 不要忽略异常:catch块禁止留空,即使预期异常不影响核心业务,也要打印日志记录,避免异常被"吞掉"。
- 保留异常链的完整信息:捕获异常后重新抛出时,要保留原始异常的cause,避免堆栈信息丢失,便于全链路问题追踪。
- 自定义异常要符合业务场景:自定义业务异常时,要继承合适的父类,区分业务异常与系统异常,携带明确的异常状态码和描述信息。
- 优先使用try-with-resources释放资源:所有可关闭的资源,都要使用try-with-resources自动释放,避免手动关闭时的资源泄漏问题。
- 异常信息要携带上下文:抛出异常时,要在描述中携带触发异常的参数、场景等上下文信息,便于快速定位问题根因。
🚨 5. 新手高频报错与解决方案
| 报错信息 | 根本原因 | 解决方案 |
|---|---|---|
java.lang.ArrayIndexOutOfBoundsException: X |
数组访问下标超出了[0, 数组长度-1]的合法范围 |
1. 检查数组的实际长度;2. 修正循环条件的边界,确保下标不超过数组长度-1;3. 访问数组前先校验下标的合法性 |
java.lang.NullPointerException: Cannot invoke "X" because "obj" is null |
对null对象调用了方法或访问了属性 |
1. 使用对象前先通过if (obj != null)判空;2. 使用JDK8+的Optional类处理可空对象;3. 初始化对象时避免赋值为null |
java.lang.ArithmeticException: / by zero |
整数除法运算中,除数为0 | 除法运算前,先判断除数是否为0,对0的场景做单独处理 |
unreported exception X; must be caught or declared to be thrown |
编译时异常没有处理,既没有try-catch捕获,也没有用throws声明 | 两种方案二选一:1. 在方法内部用try-catch捕获并处理异常;2. 在方法声明上用throws声明该异常,交给调用方处理 |
java.lang.ClassCastException: class X cannot be cast to class Y |
对不兼容的两个类型进行了强制类型转换 | 强制类型转换前,先用instanceof关键字判断对象的类型是否兼容,再进行转换 |
java.lang.NumberFormatException: For input string: "X" |
把非数字格式的字符串转换为数字类型 | 1. 转换前先校验字符串的数字格式;2. 用try-catch捕获该异常,给用户友好的格式错误提示 |
编译报错:exception X has already been caught |
多catch块中,父类异常写在了子类异常前面 | 调整catch块的顺序,将子类异常放在前面,父类异常放在后面 |
编译报错:try-with-resources not applicable to variable type X |
放入try-with-resources的资源类没有实现AutoCloseable接口 |
确保资源类实现AutoCloseable接口,并重写close()方法 |
编译报错:overridden method does not throw X exception |
子类重写父类方法时,throws声明的异常类型超出了父类方法声明的异常范围 | 子类方法声明的异常必须是父类方法声明异常的子类,或不声明异常 |
❓ 6. 常见问题FAQ
Q1:Error和Exception有什么核心区别?
A1:
Error是JVM层面的系统级致命错误,通常无法通过程序恢复,不建议主动捕获处理,发生时往往会导致JVM进程退出,比如栈溢出、内存溢出;Exception是程序级的一般性问题,可以被捕获和处理,是日常开发中异常处理的核心对象,比如数组越界、文件不存在。
Q2:运行时异常和编译时异常有什么区别?
A2:
| 特性 | 运行时异常(非受检异常) | 编译时异常(受检异常) |
|---|---|---|
| 核心类 | RuntimeException及其子类 |
除RuntimeException外的所有Exception子类 |
| 编译器检查 | 不强制处理,编译可正常通过 | 强制检查,不处理无法通过编译 |
| 触发时机 | 程序运行时 | 编译期就会校验处理逻辑 |
| 产生原因 | 代码逻辑不严谨,开发者应提前规避 | 外部环境因素,比如文件不存在、网络中断 |
Q3:finally代码块一定会执行吗?有没有例外情况?
A3:绝大多数情况下finally代码块一定会执行,唯一的例外是在try或catch块中执行了System.exit(0),该语句会强制终止当前JVM进程,JVM退出后,finally代码块就无法执行了。
Q4:throw和throws有什么区别?
A4:
throw:用于手动抛出异常对象,写在方法体内部,执行后会立即抛出一个异常对象;throws:用于声明方法可能抛出的异常,写在方法声明上,告知调用方该方法需要处理的异常类型。
Q5:如何自定义符合规范的业务异常?
A5:自定义异常需要继承合适的父类,业务异常通常继承RuntimeException(非受检异常),避免代码中到处声明异常,同时要保留异常链能力,示例如下:
java
/**
* 自定义业务异常
* 用于处理业务逻辑不符合预期的场景
*/
public class BusinessException extends RuntimeException {
/**
* 业务异常状态码,用于区分不同的业务错误类型
*/
private final int code;
/**
* 构造方法,传入异常描述信息
* @param message 异常的详细描述
*/
public BusinessException(String message) {
super(message);
this.code = 500;
}
/**
* 构造方法,传入异常状态码和描述信息
* @param code 业务异常状态码
* @param message 异常的详细描述
*/
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
/**
* 构造方法,传入异常描述和原始异常,保留异常链
* @param message 异常的详细描述
* @param cause 原始异常对象
*/
public BusinessException(String message, Throwable cause) {
super(message, cause);
this.code = 500;
}
/**
* 构造方法,传入状态码、描述和原始异常,全功能构造
* @param code 业务异常状态码
* @param message 异常的详细描述
* @param cause 原始异常对象
*/
public BusinessException(int code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
/**
* 获取异常状态码
* @return 业务异常状态码
*/
public int getCode() {
return code;
}
}
Q6:为什么不建议直接捕获Exception?
A6:直接捕获Exception会捕获到所有的运行时异常,包括我们预期之外的空指针、数组越界等异常,导致这些代码逻辑问题被隐藏,无法及时发现和修复。正确的做法是捕获具体的异常类型,只处理我们预期内的异常。
Q7:JDK21中,异常处理有哪些适配优化和最佳实践?
A7:JDK21作为最新的LTS版本,完全兼容之前版本的异常处理语法,同时针对虚拟线程(Virtual Thread)场景做了专项优化:虚拟线程的异常堆栈会完整保留载体线程与虚拟线程的上下文信息,便于排查并发场景的异常问题;同时JDK21增强了异常堆栈的可读性,默认会省略JDK内部的无关堆栈帧,大幅提升问题排查效率。
针对JDK21的专属最佳实践:在虚拟线程场景中,建议统一捕获线程顶级异常,避免虚拟线程异常静默丢失;优先使用try-with-resources管理资源,适配虚拟线程的资源隔离模型。
💻 7. 完整实战案例
本案例结合文件读取、参数校验、异常处理的全流程,基于JDK21编写,可直接运行,覆盖了本文的核心知识点。
java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
* Java异常处理完整实战案例
* 功能:读取指定路径的文本文件,统计文件的行数
* 覆盖:参数校验、异常捕获、资源自动释放、自定义异常、异常链传递
*/
public class FileLineCountDemo {
public static void main(String[] args) {
// 要统计的文件路径
String targetFilePath = "test.txt";
try {
// 调用方法统计文件行数
int lineCount = countFileLines(targetFilePath);
System.out.println("文件读取完成,总行数为:" + lineCount);
} catch (BusinessException e) {
// 捕获自定义业务异常,给用户友好提示
System.err.println("业务处理失败:" + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
// 捕获其他未预期的异常,兜底处理
System.err.println("系统异常,操作失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 统计文本文件的行数
* @param filePath 文件路径,不能为空
* @return 文件的总行数
* @throws BusinessException 业务异常,参数非法或文件读取失败时抛出
*/
public static int countFileLines(String filePath) {
// 1. 参数合法性校验
if (filePath == null || filePath.isBlank()) {
// 参数为空,手动抛出自定义业务异常
throw new BusinessException(400, "文件路径不能为空");
}
int lineCount = 0;
// 2. try-with-resources自动管理文件流资源
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
String lineContent;
// 3. 循环读取文件每一行,统计行数
while ((lineContent = bufferedReader.readLine()) != null) {
lineCount++;
}
} catch (IOException e) {
// 4. 捕获IO异常,包装为业务异常抛出,保留原始异常链
throw new BusinessException(500, "文件读取失败,路径:" + filePath + ",错误信息:" + e.getMessage(), e);
}
// 5. 返回统计结果
return lineCount;
}
}
🔗 权威参考链接
如果本文对你有帮助,欢迎点赞👍、收藏⭐、评论💬、关注➕!
个人领域:C++/java/Al/软件开发/芯片开发
个人主页:「一名热衷协作的开发者,在构建中学习,期待与你交流技术、共同成长。」座右铭:「与其完美地观望,不如踉跄地启程」

