打印一段数据到控制台是再平常不过的操作,但直接用 System.out.println 拼字符串,遇到列数较多的表格数据时输出往往参差不齐,可读性很差。Java 从 J2SE 5.0 开始引入了 C 风格的格式化输出方法 printf,它通过格式化字符串配合占位符,可以精确控制每个字段的对齐方式、宽度、小数位数甚至千分位符号,是命令行报表、调试输出和算法题目展示的利器。本文将系统讲解 printf 的语法结构、对齐技巧与常见坑点。

一、printf 的基本语法与格式化占位符
printf 的方法签名是 printf(String format, Object... args),第一个参数是格式化字符串,后面的可变参数会依次填充到字符串中的占位符里。占位符以百分号开头,完整结构如下:
System.out.printf("%[参数索引$][标志][宽度][.精度]转换符", value);
其中最核心的是转换符,它决定了值以什么类型展示。常用的有:%d 表示整数,%f 表示浮点数,%s 表示字符串,%c 表示字符,%b 表示布尔值,%x 表示十六进制整数,%e 表示科学计数法。宽度指最小字符数,不足时默认用空格在左侧补齐,也就是右对齐;精度对浮点数来说是小数位数,对字符串来说则是最大截取长度。
下面用一个简单例子感受一下各转换符的效果:
int id = 1001;
String name = "张三";
double salary = 8500.5678;
System.out.printf("工号: %d, 姓名: %s, 工资: %.2f%n", id, name, salary);
// 输出: 工号: 1001, 姓名: 张三, 工资: 8500.57
注意这里的 %n 是平台相关的换行符,Windows 下是 \r\n,Linux 下是 \n,比直接写 \n 更规范。很多人写 %.2f 时会疑惑四舍五入的规则,Java 使用的是 HALF_UP 舍入模式,也就是常见的四舍五入,所以 8500.5678 输出为 8500.57。
二、对齐与补齐:让表格数据整齐排列
格式化最有价值的应用就是表格输出。宽度控制配合标志位,可以实现左对齐、右对齐、补零等效果。常用的标志位有:负号 - 表示左对齐,0 表示用零填充,逗号 , 表示千分位分组,加号 + 表示正数也显示符号。
比如打印一份员工工资表,希望表头和每一列数据都对齐,可以这样做:
System.out.printf("%-10s%8s%12s%n", "姓名", "工号", "月薪");
System.out.printf("%-10s%8d%,12.2f%n", "张三", 1001, 8500.5678);
System.out.printf("%-10s%8d%,12.2f%n", "李四", 1002, 12345.6);
System.out.printf("%-10s%8d%,12.2f%n", "王五", 1003, 4500);
// 输出效果(注意中文占两个显示宽度):
// 姓名 工号 月薪
// 张三 1001 8,500.57
// 李四 1002 12,345.60
// 王五 1003 4,500.00
这里 %-10s 表示字符串左对齐占 10 个字符宽度,%8d 表示整数右对齐占 8 位,%,12.2f 表示浮点数总宽 12 位、保留两位小数并加千分位逗号。数值列用右对齐是表格排版的惯例,这样小数点天然对齐,数值大小一目了然。
需要提醒的是,中文在控制台中通常占用两个显示宽度,但 printf 的宽度按字符数计算而不是显示宽度,所以纯中文字段的对齐可能出现偏差。解决办法是手动按中文字符数量加宽字段,或者编写一个工具方法计算字符串的显示宽度后再决定补几个空格。补零的场景多见于编号和日期,例如 %05d 会把 42 显示成 00042,常见于订单号、流水号的格式化。
三、进阶用法:参数索引与日期时间格式化
参数索引允许重复引用同一个参数,写法是在占位符中加 n$。最典型的例子是打印日期,同一个 Date 对象的不同部分分别格式化:
import java.util.Date;
Date now = new Date();
System.out.printf("现在是 %1$tY年%1$tm月%1$td日 %1$tH:%1$tM:%1$tS%n", now);
// 输出示例: 现在是 2024年06月15日 09:30:45
%t 系列转换符专门用于日期时间,其中 tY 是四位年份,tm 是两位月份,td 是两位日期,tH、tM、tS 分别是时、分、秒。如果不写参数索引,每个占位符会消耗一个参数,就会报错,因为 Date 只传了一次。当然实际项目中更推荐用 java.time.format.DateTimeFormatter 处理日期,但快速调试时 printf 的写法更省事。
四、printf 与 String.format、DecimalFormat 的选择
三者底层都依赖 java.util.Formatter,但适用场景不同。String.format 返回格式化后的字符串而不直接打印,适合把结果存入变量、拼接进日志或者写入文件;printf 等价于 System.out.print(String.format(...)),纯粹为了输出;DecimalFormat 则专注数字格式化,支持自定义模式,例如保留小数、百分比、自定义货币符号等,灵活度比 %.2f 更高。
import java.text.DecimalFormat;
// 用 DecimalFormat 自定义百分比格式
DecimalFormat df = new DecimalFormat("0.00%");
System.out.println(df.format(0.7856)); // 输出: 78.56%
// 用 String.format 生成字符串供日志使用
String log = String.format("用户%s登录,耗时%dms", "admin", 335);
logger.info(log);
最后说几个常见的坑。第一,占位符与参数类型不匹配会抛 IllegalFormatConversionException,比如用 %d 去格式化一个 double,编译期不会报错,运行时才炸,所以类型要对应好。第二,浮点数直接比较和格式化都可能受二进制精度影响,金额计算建议先换成 BigDecimal 再格式化。第三,%% 才能输出百分号本身,直接写单个 % 会抛 UnknownFormatConversionException。掌握这些细节后,无论是打印调试信息还是生成命令行报表,输出都会规整专业很多。
Java printf格式化输出控制台对齐修改时间:2026-09-12 13:30:37