1. 概述
本文将演示如何在 Java 中使用 SLF4J 日志门面 API 来记录异常。我们将采用 slf4j-simple
作为底层日志实现。
如果你对更多日志技术感兴趣,可以参考我们之前的日志专题文章。
⚠️ 注意:本文重点在于异常的正确记录方式,而不是日志框架的配置或选型。踩坑最多的往往不是技术本身,而是怎么用。
2. Maven 依赖
要使用 SLF4J,首先需要引入以下两个核心依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
✅ 推荐:始终在 Maven Central 上检查最新版本,避免使用过时依赖。
✅ 提示:生产环境通常不会用
slf4j-simple
,而是桥接到 Logback 或 Log4j2。这里只是为了演示简洁。
3. 异常记录示例
SLF4J 的 Logger
接口提供了多个 error()
方法重载,用于处理不同场景下的异常记录。最常用的有以下三种形式:
void error(String msg);
void error(String format, Object... arguments);
void error(String msg, Throwable t);
3.1 初始化 Logger
标准写法,每个类都应有自己的 Logger 实例:
Logger logger = LoggerFactory.getLogger(ExceptionLoggingExample.class);
3.2 只记录错误信息 ❌(不推荐)
logger.error("An exception occurred!");
输出结果:
ERROR com.example.ExceptionLoggingExample - An exception occurred!
⚠️ 问题:没有堆栈信息!这种写法等于白记,出了问题根本没法定位。
3.3 正确记录异常 ✅(推荐)
必须把异常对象作为第二个参数传入:
logger.error("An exception occurred!", new Exception("Custom exception"));
输出结果:
ERROR com.example.ExceptionLoggingExample - An exception occurred!
java.lang.Exception: Custom exception
at com.example.ExceptionLoggingExample.main(ExceptionLoggingExample.java:15)
✅ 关键点:
- 异常的完整堆栈被打印
- 错误上下文清晰(消息 + 异常)
- 调试时可以直接定位到出错行
3.4 带参数的格式化日志 + 异常 ✅
当需要动态拼接日志内容时,使用占位符 {}
:
logger.error("{}, {}! An exception occurred!",
"Hello",
"World",
new Exception("Custom exception"));
输出结果:
ERROR com.example.ExceptionLoggingExample - Hello, World! An exception occurred!
java.lang.Exception: Custom exception
at com.example.ExceptionLoggingExample.main(ExceptionLoggingExample.java:20)
⚠️ 重要机制:
- SLF4J 会自动识别:如果最后一个参数是 Throwable 类型,就把它当作异常处理
- 前面的
{}
会被前面的 Object... 参数依次替换 - 不要手动调用
e.toString()
或拼接字符串,否则堆栈丢失!
❌ 常见错误写法(千万别这么干)
// 错误 1:把异常转成字符串
logger.error("Error: " + new Exception("msg"));
// 错误 2:异常放在中间参数
logger.error("Error: {}, exception: {}", "test", new Exception("msg"));
// 错误 3:用 String.format
logger.error(String.format("Error: %s", "test"), new Exception("msg"));
以上三种写法都会导致:
- 堆栈信息无法正常输出
- 或者异常被当成普通参数打印
- 日志可读性极差
4. 总结
使用 SLF4J 记录异常的关键点总结如下:
✅ 正确姿势:
- 使用
error(String msg, Throwable t)
形式 - 格式化日志时,异常必须是最后一个参数
- 使用
{}
占位符,避免字符串拼接
❌ 避坑指南:
- 不要手动
.toString()
异常 - 不要把异常放在中间参数位置
- 不要用
String.format
预处理日志消息
简单粗暴一句话:只要有异常,就把它传给 error 方法的最后一个参数,SLF4J 自动帮你搞定格式和堆栈。
掌握这一点,你的日志才真正具备可调试价值。否则,线上出问题时,日志就是一堆废纸。