推荐使用日志框架原生支持(如SLF4J的log.error("msg", e))记录异常,避免printStackTrace();手动处理需用getStackTrace()+toString()拼接;重抛异常须传cause或用throw e保留原始堆栈。

直接调用 printStackTrace() 最快但不灵活
最常见做法是捕获异常后调用 e.printStackTrace(),它会把堆栈信息输出到 System.err。适合开发调试,但无法控制输出位置或格式,线上环境容易干扰日志结构。
- 不推荐在生产代码中使用,尤其不能和日志框架混用(比如 SLF4J +
printStackTrace()会导致日志行错乱) - 如果必须用,建议重定向到
PrintWriter写入字符串:new StringWriter().getBuffer().toString(),便于后续处理 - 注意:该方法不抛出异常,也不返回值,纯副作用操作
用 Exception.toString() 和 getStackTrace() 手动拼接
当需要自定义输出格式(比如只取前 3 层、过滤某些类名、加时间戳),就得手动处理堆栈元素。核心是 e.getStackTrace() 返回 StackTraceElement[] 数组。
-
e.toString()给出异常类型 + 消息,如java.lang.NullPointerException: Cannot invoke "String.length()" because "s" is null - 遍历
e.getStackTrace()可逐行获取类名、方法名、文件名和行号,适合做脱敏(如隐藏内部包路径) - 性能上比
printStackTrace()略低,但可控性强;注意不要在高频路径中反复拼接长堆栈
Logback / Log4j2 中正确记录异常堆栈
主流日志框架对异常有原生支持,传入 Throwable 参数即可自动展开堆栈,无需手动处理。
- SLF4J 示例:
log.error("DB query failed", e);—— 第二个参数是Throwable,框架会完整打印堆栈 - 错误写法:
log.error("DB query failed: " + e);或log.error("DB query failed", e.toString());,只会输出消息,丢掉堆栈 - Logback 配置中确保
%ex或%xEx在 pattern 里启用,否则可能被截断
捕获异常后重新抛出时保留原始堆栈
用 throw e; 而不是 throw new RuntimeException(e);,否则原始堆栈会被覆盖,丢失根因位置。
立即学习“Java免费学习笔记(深入)”;
- 想包装异常又保留堆栈?用带
cause的构造函数:throw new ServiceException("order process failed", e); - JDK 7+ 支持
addSuppressed(),适用于 try-with-resources 中多个异常并存的场景 - 避免在 catch 块里只写
log.error("", e); throw new XxxException();却不传 cause —— 这是最隐蔽的堆栈丢失点











