SLF4J通过{}占位符实现延迟格式化,仅当日志级别启用时才解析参数,避免无谓字符串拼接开销;支持多参数、自动处理null及末尾异常,显著提升性能与安全性。

Java 中日志打印占位符参数,核心是避免字符串拼接,用支持参数化日志的框架(如 SLF4J)配合占位符 {},让日志框架在真正需要输出时才格式化,既提升性能又防止空指针或类型错误。
SLF4J + Logback:标准推荐方式
SLF4J 是 Java 最主流的日志门面,底层可对接 Logback、Log4j2 等实现。它原生支持花括号占位符,且支持多个参数、自动处理 null 和异常。
- 单个参数:
logger.info("User id: {}", userId); - 多个参数:
logger.debug("Login attempt from {} at {}, status: {}", ip, timestamp, result); - 带异常堆栈:
logger.error("Failed to process order {}", orderId, ex);(异常必须放最后,不参与占位)
为什么不用 String.format 或 + 拼接?
直接拼接(如 "id=" + id + ", name=" + name)会在每次调用时无条件构造字符串,即使日志级别被禁用(如 debug 关闭),也白白消耗 CPU 和内存。而占位符方式只在日志实际启用时才解析参数,更高效安全。
注意:String.format("id=%s", id) 同样会提前格式化,不属于“延迟求值”,不推荐用于高频日志。
立即学习“Java免费学习笔记(深入)”;
Log4j2 的等效写法(兼容占位符)
Log4j2 也支持 {} 占位符,用法与 SLF4J 高度一致:
logger.info("Order processed: {}, amount: {}", orderId, amount);- 同样支持末尾传 Throwable:
logger.warn("Cache miss for key {}", key, e);
但需确保使用的是 Log4j2 的 org.apache.logging.log4j.Logger,而非旧版 Log4j 1.x(后者不支持该语法,需用 %s 配合 String.format,已不建议)。
常见陷阱与建议
占位符看着简单,但几个细节容易出错:
- 占位符数量必须严格匹配参数个数,多或少都会报错或静默丢参
- 不要写成
"{} ms".format(elapsed)—— 这是 String 的方法,不是日志框架的占位符 - 参数为对象时,会自动调用
toString();若对象可能为 null,SLF4J 会显示null字符串,不会 NPE - 敏感信息(如密码、token)切勿打日志,占位符也不能豁免 —— 先脱敏再传入



















