SLF4J 使用 {} 占位符可避免日志禁用时的无效字符串拼接,节省 CPU 和内存;支持最多 3 个参数,超限时用可变参数;仅在日志启用时格式化,对 null 安全,异常须置于参数末尾。

Java 中使用 SLF4J(Simple Logging Facade for Java)的日志框架时,用 {} 占位符替代字符串拼接,能避免在日志级别被禁用时仍执行无意义的字符串构造,从而节省 CPU 和内存开销。
占位符的基本用法
SLF4J 的 logger.info("User {} logged in at {}", username, timestamp) 会在日志级别允许输出时才真正格式化字符串;如果当前日志级别是 WARN 或 ERROR,username 和 timestamp 的字符串拼接根本不会发生。
- 支持最多 3 个参数:
info(String format, Object arg1, Object arg2, Object arg3) - 超过 3 个参数时,用可变参数形式:
info(String format, Object... arguments) - 占位符只识别
{},不支持{0}、%s等其他格式
与字符串拼接的性能对比
直接拼接如 logger.info("User " + username + " logged in at " + timestamp) 会强制执行所有字符串运算,无论日志是否实际输出。而占位符方式只在需要打印时才调用 String.format 或内部解析逻辑。
- 当 INFO 日志被关闭(如生产环境设为 WARN),拼接版仍创建临时 String 对象,触发 GC 压力
- 占位符版跳过格式化,仅传入原始对象引用,开销几乎为零
- 尤其在高频日志(如循环内、热点路径)中差异显著
处理复杂对象和 null 安全
占位符自动调用对象的 toString(),对 null 值也安全(输出 null 字符串,不会抛 NPE)。
立即学习“Java免费学习笔记(深入)”;
- 无需手动判空或调用
String.valueOf(obj) - 若需自定义输出,重写对象的
toString()即可 - 避免在占位符外提前调用
obj.toString(),否则失去懒加载优势
异常日志的正确写法
记录异常时,应把 Throwable 放在参数列表末尾,SLF4J 会自动识别并打印堆栈:
- ✅ 正确:
logger.error("Failed to process order {}", orderId, ex) - ❌ 错误:
logger.error("Failed to process order " + orderId + ": " + ex)—— 拼接且丢失结构化异常信息 - 注意:异常必须是最后一个参数,且不能放进
{}占位符里



















