不该直接 new Formatter() 做字符串格式化,因其设计初衷是绑定 Appendable(如 StringBuilder、FileWriter),不返回字符串且需手动 toString()、flush() 或 close(),易出错;应优先使用 String.format() 或 System.out.printf()。

Java 的 Formatter 类不是“格式化工具”,它是一个底层的、面向字符流的格式化引擎,不直接用于日常字符串拼接或日志输出;真正该用的是 String.format()、System.out.printf() 或 MessageFormat。
为什么不该直接 new Formatter() 做字符串格式化
Formatter 设计初衷是绑定到某个 Appendable(如 StringBuilder、FileWriter、PrintStream),它本身不返回字符串,也不缓存结果。手动用它拼字符串既冗余又易错。
- 必须显式传入
Appendable,比如new Formatter(new StringBuilder()) - 调用
format()后需手动调用toString()(如果底层是StringBuilder)才能拿到结果 - 忘记关闭或重用实例可能引发状态残留(如 locale、flags 被污染)
- 相比
String.format(),没有异常自动包装(IllegalFormatConversionException会直接抛出,不转成RuntimeException)
Formatter.format() 和 String.format() 的参数完全一致
所有转换符(%s、%d、%f)、标志(- 左对齐、0 补零)、宽度、精度写法都一样,区别只在调用方式和目标对象。
String s1 = String.format("Name: %s, Age: %d", "Alice", 30); // ✅ 简洁安全
StringBuilder sb = new StringBuilder();
Formatter f = new Formatter(sb);
f.format("Name: %s, Age: %d", "Alice", 30); // ✅ 参数相同,但步骤多
String s2 = sb.toString();
注意:Formatter 不支持 null 安全——若传入 null 给 %s,会输出字符串 "null",而非抛异常;而 String.format() 行为一致,这点无差异。
立即学习“Java免费学习笔记(深入)”;
Formatter 的真实适用场景:定制输出目标
只有当你需要把格式化结果写入非内存目标时,Formatter 才不可替代:
- 写入文件:
new Formatter(new FileWriter("log.txt")) - 写入 Socket 输出流:
new Formatter(socket.getOutputStream()) - 配合自定义
Appendable实现日志缓冲、长度截断等逻辑
此时要注意:必须显式调用 flush() 或 close()(尤其涉及 I/O 流时),否则内容可能滞留在缓冲区中不落地。
常见错误:忽略 locale 导致数字/日期格式异常
Formatter 默认使用 JVM 启动时的默认 locale,但 String.format() 也是。问题常出现在多线程环境或动态切换 locale 的应用中:
- 用
new Formatter(appendable, Locale.US)显式指定 locale,避免千分位符、小数点变成逗号 - 不要依赖
Formatter.getInstance()(不存在!这是常见误记) - 日期格式化慎用
%t系列:它依赖 locale 的缩写和顺序,Locale.CHINA下%tF是yyyy-MM-dd,Locale.US下仍是同格式,但%tc输出差异极大
真正难处理的是嵌套格式(如动态字段宽度:%),这种写法可读性差、调试困难,建议拆成两步或改用 MessageFormat。










