Java从入门到精通(四):异常处理实战(Exception体系、全局处理与日志落地)
Java从入门到精通四异常处理实战Exception体系、全局处理与日志落地这是“Java从入门到精通”系列第4篇。前面我们讲了语法、面向对象、集合这篇进入工程开发中最容易被忽略却最关键的一环异常处理。目标很明确你要学会写出“可定位、可恢复、可维护”的异常处理代码而不是只会 try-catch。一、学习目标搞清楚 Throwable / Error / Exception 的关系。理解 checked exception 和 unchecked exception 的使用边界。掌握自定义异常、异常包装、统一异常响应。完成一个可运行的订单服务示例含日志。二、异常体系快速梳理Java异常根类是Throwable分成两大支Error系统级错误通常不处理如 OOM。Exception业务可预期异常开发者需要处理。Exception又分两类Checked Exception编译器强制处理如 IOException。Unchecked Exception运行时异常如 NullPointerException、IllegalArgumentException。三、什么时候用 checked什么时候用 unchecked工程里常见原则外部资源、可恢复场景优先 checked文件、网络、IO。参数非法、状态冲突、编程错误优先 unchecked。不要滥用 checked exception否则方法签名会被污染调用链维护成本陡增。四、异常处理三条硬规则不要吞异常空catch是事故源头。不要丢失上下文包装时保留 cause。不要把底层异常直接暴露给用户统一转换。五、可运行实战订单服务异常链路import java.util.*; import java.util.logging.Logger; class BizException extends RuntimeException { private final String code; public BizException(String code, String message) { super(message); this.code code; } public BizException(String code, String message, Throwable cause) { super(message, cause); this.code code; } public String getCode() { return code; } } class OrderService { private static final Logger log Logger.getLogger(OrderService); private final MapString, Integer inventory new HashMap(); public OrderService() { inventory.put(book, 10); inventory.put(pen, 3); } public String createOrder(String sku, int count) { validateParam(sku, count); try { int stock queryStock(sku); if (stock count) { throw new BizException(STOCK_NOT_ENOUGH, 库存不足); } inventory.put(sku, stock - count); return ORDER- System.currentTimeMillis(); } catch (BizException e) { log.warning(业务异常 code e.getCode() , msg e.getMessage()); throw e; } catch (Exception e) { log.severe(系统异常: e.getMessage()); throw new BizException(SYS_ERROR, 系统繁忙请稍后重试, e); } } private void validateParam(String sku, int count) { if (sku null || sku.isBlank()) { throw new IllegalArgumentException(sku不能为空); } if (count 0) { throw new IllegalArgumentException(count必须大于0); } } private int queryStock(String sku) { if (!inventory.containsKey(sku)) { throw new BizException(SKU_NOT_FOUND, 商品不存在: sku); } return inventory.get(sku); } } public class Main { public static void main(String[] args) { OrderService service new OrderService(); try { String orderId service.createOrder(book, 2); System.out.println(下单成功: orderId); } catch (Exception e) { System.out.println(失败: e.getMessage()); } try { service.createOrder(pen, 10); } catch (Exception e) { System.out.println(失败: e.getMessage()); } try { service.createOrder(, 1); } catch (Exception e) { System.out.println(失败: e.getMessage()); } } }运行方式javac Main.java java Main六、Web项目中的全局异常处理Spring Boot后端项目建议统一输出错误码避免前端拿到不稳定错误格式。RestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(BizException.class) public ResponseEntityMapString, Object handleBiz(BizException e) { MapString, Object body new HashMap(); body.put(code, e.getCode()); body.put(message, e.getMessage()); return ResponseEntity.badRequest().body(body); } ExceptionHandler(Exception.class) public ResponseEntityMapString, Object handleEx(Exception e) { MapString, Object body new HashMap(); body.put(code, SYS_ERROR); body.put(message, 系统异常); return ResponseEntity.status(500).body(body); } }七、日志落地建议业务异常warn级别带业务code。系统异常error级别保留堆栈。统一日志字段traceId、userId、uri、code。核心原则日志是给“未来排障的你”看的不是给当前开发者看的。八、常见误区catch (Exception e)后直接返回“失败”不记录日志。自定义异常不带错误码导致前后端约定混乱。把底层SQLException直接抛给接口层泄漏内部实现。finally里做return覆盖真实异常。九、总结与下篇预告异常处理的本质是“故障管理能力”。写好异常系统才具备稳定运行与快速恢复的基础。下一篇进入IO/NIO文件读写、缓冲区、Channel、零拷贝和实战文件服务。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2409248.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!