string.formatted因严格类型检查而抛illegalformatconversionexception,不支持自动装箱或隐式拆箱,如"%d".formatted(integer.valueof(42))报错,而"%d".formatted(42)正常。

String.formatted 为什么调用就抛 IllegalFormatConversionException
因为 String.formatted 是严格类型检查的,它不会自动装箱或类型转换。比如把 int 传给 %s 没问题,但传给 %d 时如果实际是 Integer(而非 int),就会炸——JVM 看的是运行时类型,不是声明类型。
-
"%d".formatted(Integer.valueOf(42))→ 报错;"%d".formatted(42)→ 正常 - 泛型集合里取出来的数字(如
list.get(0))大概率是Object或包装类,直接塞进%d/%f就踩坑 - 和
String.format不同,formatted不做隐式拆箱,出错更早、更明确,但对动态数据更“脆”
String.formatted 和 String.format 到底该用哪个
优先用 String.formatted,前提是格式串固定、参数类型可控;否则退回 String.format。
-
formatted是实例方法,语义更清晰(“这个字符串按这些值填”),且 JIT 可能优化更好 -
String.format是静态方法,兼容老代码,支持Locale重载,还能接Appendable,formatted没这功能 - 如果格式串来自配置或用户输入,别用
formatted—— 它不校验格式串合法性,错在运行时才爆IllegalFormatException
Java 15+ 项目里怎么安全迁移 printf 风格代码
不能全局替换,得看上下文。重点盯住三类地方:日志拼接、SQL 拼接、模板渲染。
- 日志场景(如
log.info("user {} login from {}", userId, ip))→ 改用formatted安全,SLF4J 的占位符机制已屏蔽类型风险 - SQL 拼接(如
"SELECT * FROM t WHERE id = %d".formatted(id))→ 禁止!必须用 PreparedStatement,formatted不防 SQL 注入 - 需要
Locale控制小数点/千分位时(如财务显示),formatted不支持,只能留String.format(Locale.CHINA, "%.2f", amount)
Android 上能不能用 String.formatted
不能直接用,除非你只支持 Android API 30+(即 Android 11)。
立即学习“Java免费学习笔记(深入)”;
- Java 15 特性,Android Runtime(ART)直到 API 30 才开始逐步对齐 Java 15+ 的核心库行为
- 低版本会报
NoSuchMethodError: java.lang.String.formatted,连编译都过不去(如果 targetSdk - 替代方案:保持
String.format,或封装一层兼容逻辑(检查方法是否存在再反射调用,但太重,不推荐)
最易被忽略的是:IDE 可能不报错(因为编译用的是 JDK,不是 Android SDK),但一跑就崩。真要上 formatted,务必在 build.gradle 里确认 compileSdk 和 targetSdk 都 ≥ 30。










