异常
2025/12/3大约 3 分钟
说一下Java异常体系结构
Java异常基于Throwable类,分为两大分支:
- Error:JVM严重错误,如
OutOfMemoryError、StackOverflowError - Exception:程序可处理异常
- 受检异常:编译时强制处理,如
IOException、FileNotFoundException - 运行时异常:继承自
RuntimeException,如NullPointerException、ArrayIndexOutOfBoundsException
- 受检异常:编译时强制处理,如
Java的异常处理机制有哪些?
1. try-catch-finally
try {
// 可能会异常的代码
} catch (SpecificException e) {
// 处理特定异常
} catch (Exception e) {
// 处理其他异常
} finally {
// 总是执行的代码(资源清理)
}2. throw和throws
// 手动抛出异常
public void check(int value) {
if (value < 0) throw new IllegalArgumentException("值不能为负数");
}
// 方法声明抛出异常
public void read() throws IOException {
// 可能抛出IOException的代码
}下面是 结构更清晰、重点更突出、可读性更强、面试更易背的优化版本(保留你的内容,但做了精炼与格式增强)。
现代主流的异常处理机制是什么?
异常链(Exception Chaining)
- 核心作用:保留原始异常,方便排查根因
- 通过构造方法把原异常作为
cause传递下去
try {
userService.getUser(userId); // 可能抛出 SQLException
} catch (SQLException e) {
// 包装异常,同时保留原始异常信息
throw new ServiceException("服务调用失败", e);
}为什么需要异常链?
- 保留根因:知道是 SQL 写错?网络故障?连接池问题?
- 调试友好:异常栈完整,从业务层→DAO层链路清晰
- 跨层传递不丢信息:适合分层架构(Controller → Service → DAO)
Try-With-Resources(Java 7+)
- 自动关闭资源,防止资源泄漏
- 替代 finally 的繁琐写法
try (FileInputStream in = new FileInputStream("a.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// 使用资源
} catch (IOException e) {
// 异常处理
}异常处理最佳实践
自定义异常(业务强相关)
意义:让业务语义更清晰,例如
OrderException、UserNotFoundException可继承
Exception(受检)RuntimeException(非受检)
public class BusinessException extends Exception {
private String code;
public BusinessException(String msg) { super(msg); }
public BusinessException(String msg, String code) {
super(msg);
this.code = code;
}
}使用示例:
public void processOrder(Order order) throws BusinessException {
if (order == null) {
throw new BusinessException("订单不能为空", "ORDER_NULL");
}
}异常处理策略
- 记录日志:日志里保存完整错误(包括堆栈)
- 优雅降级:服务不可用时快速返回默认值 / fallback
- 监控告警:异常接入 Prometheus、Sentry、SkyWalking
函数式异常处理(Java 8+)
- 减少 if-null 判断
- 减少大量 try-catch
// null 安全
String result = Optional.ofNullable(getData())
.map(String::toUpperCase)
.orElse("默认值");
// Stream 异常处理
List<String> list2 = list.stream()
.map(this::safeParse) // 返回 Optional
.flatMap(Optional::stream) // 过滤空值
.collect(Collectors.toList());全局异常处理(Web 常用)
- 完全不用在 Controller 中写 try-catch
- 实现统一响应格式(JSON)
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<?> handleBiz(BusinessException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleAll(Exception e) {
return ResponseEntity.status(500).body("系统异常");
}
}Java类加载中常见的异常类有哪些?
ClassNotFoundException
- 类型:编译时检查异常(受检异常)
- 原因:
Class.forName("xxx")或类路径中找不到指定类
NoClassDefFoundError
- 类型:运行时错误(Error)
- 原因:编译时存在类,但运行时 JVM 找不到(可能类路径变动或依赖缺失)
- 区别:
ClassNotFoundException是主动加载失败,NoClassDefFoundError是被动引用失败
ClassFormatError
- 类型:运行时错误
- 原因:类文件格式错误或被篡改,不符合 JVM 规范
UnsupportedClassVersionError
- 类型:运行时错误
- 原因:类文件版本高于当前 JVM 版本
- 示例:用 JDK 17 编译的类在 JDK 11 上运行
LinkageError系列
VerifyError:字节码校验失败NoSuchMethodError/NoSuchFieldError:类的结构变化导致方法或字段找不到