ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

HoRain云--Java异常处理最佳实践与性能优化

HoRain云--Java异常处理最佳实践与性能优化

异常处理看似简单,实则暗藏玄机。异常影响性能吗?该捕获还是抛出?finally一定会执行吗?本文系统讲解Java异常处理。

一、异常体系

text

复制

下载

Throwable ├── Error(不可恢复) │ ├── OutOfMemoryError │ └── StackOverflowError └── Exception ├── RuntimeException(非受检) │ ├── NullPointerException │ └── IllegalArgumentException └── 受检异常 ├── IOException └── SQLException

二、受检 vs 非受检

  • 受检异常:必须处理或声明,用于可恢复场景

  • 非受检异常:编程错误,如NPE

java

复制

下载

// 受检异常 public void read() throws IOException { Files.readAllBytes(Path.of("file.txt")); } // 非受检 public void validate(String s) { if (s == null) throw new IllegalArgumentException("不能为null"); }

三、异常的性能

创建异常需要填充栈轨迹,开销较大。

java

复制

下载

// 慢:用异常控制流程 try { while (true) { arr[index++] = getValue(); } } catch (ArrayIndexOutOfBoundsException e) { // 结束 } // 快:正常判断 while (index < arr.length) { arr[index++] = getValue(); }

优化:重写fillInStackTrace避免填充栈。

java

复制

下载

public class LightException extends RuntimeException { @Override public synchronized Throwable fillInStackTrace() { return this; } }

四、try-catch-finally

java

复制

下载

public int test() { try { return 1; } finally { return 2; // 覆盖try的return,不推荐 } } // 返回2

finally不执行的情况:

  • System.exit()

  • JVM崩溃

  • 死循环

五、try-with-resources

java

复制

下载

// 旧方式 BufferedReader br = null; try { br = new BufferedReader(new FileReader("file.txt")); return br.readLine(); } finally { if (br != null) br.close(); } // 新方式 try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) { return br.readLine(); }

自定义资源需实现AutoCloseable:

java

复制

下载

public class MyResource implements AutoCloseable { @Override public void close() { System.out.println("关闭资源"); } }

六、异常链

保留原始异常信息:

java

复制

下载

try { // ... } catch (SQLException e) { throw new ServiceException("查询失败", e); }

java

复制

下载

public class ServiceException extends RuntimeException { public ServiceException(String msg, Throwable cause) { super(msg, cause); } }

七、异常处理反模式

7.1 吞掉异常

java

复制

下载

// 坏 try { doSomething(); } catch (Exception e) { // 什么都不做 } // 好 try { doSomething(); } catch (Exception e) { log.error("操作失败", e); throw new ServiceException("操作失败", e); }
7.2 捕获过宽

java

复制

下载

// 坏 try { // ... } catch (Exception e) {} // 好 try { // ... } catch (IOException e) { // 处理I/O异常 } catch (SQLException e) { // 处理数据库异常 }
7.3 用异常控制流程

java

复制

下载

// 坏 try { return map.get(key).getValue(); } catch (NullPointerException e) { return defaultValue; } // 好 Value v = map.get(key); return v != null ? v.getValue() : defaultValue;

八、全局异常处理

Spring Boot中:

java

复制

下载

@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public Result<Void> handleBusiness(BusinessException e) { return Result.error(e.getCode(), e.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) public Result<Void> handleValidation(MethodArgumentNotValidException e) { String msg = e.getBindingResult().getFieldErrors().stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining(", ")); return Result.error(400, msg); } @ExceptionHandler(Exception.class) public Result<Void> handleUnknown(Exception e) { log.error("未知异常", e); return Result.error(500, "系统繁忙"); } }

九、最佳实践

  1. 不要吞异常,至少记录日志

  2. 捕获具体异常,不要catch Exception

  3. 用异常链保留原因

  4. 不要用异常控制流程

  5. 受检异常用于可恢复场景

  6. 资源用try-with-resources

  7. 自定义异常继承RuntimeException

  8. 异常信息要具体,包含关键参数

十、总结

异常处理的核心是"不吞、不滥用、保留上下文"。合理的异常设计能提升系统可维护性和可观测性。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进