首页 / Java 入门教程 / 字符串格式化:format、printf 与文本块

Java 入门教程

字符串格式化:format、printf 与文本块

本教程共 100 篇 · 第 57 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

JavaJava 入门教程格式化String.format文本块

57. 字符串格式化

本节目标:掌握用占位符把变量整齐塞进字符串的几种方式,看懂常用格式符,并学会用文本块写多行字符串。

拼字符串除了用 + 和 StringBuilder,还有一种更干净的办法:格式化。想象一张填空题模板,先留好空位,运行时再把具体数值填进去。

为什么要格式化

看一段用加号拼的欢迎语:

String msg = "你好," + name + "!你第 " + count + " 次登录,积分 " + score + "。";
```text

加号满天飞,文字和变量搅在一起,标点空格藏在引号缝里,改一个字都提心吊胆。换成格式化,模板和数据彻底分开:

```java
String msg = "你好,%s!你第 %d 次登录,积分 %d。".formatted(name, count, score);

一眼就能看出这句话长什么样。%s%d 是坑位,后面按顺序把变量递进去填。做国际化时更明显——模板可以整句抽到配置文件里翻译,变量位置不动。

三种入口:format、formatted、printf

第一种,静态方法 String.format,返回拼好的字符串:

String s = String.format("价格:%d 元", 99);
```text

第二种,实例方法 `formatted()`,Java 15 加到 String 上,把模板放在最前面,读起来更顺:

```java
String s = "价格:%d 元".formatted(99);

第三种,直接打印到控制台的 printf,名字里的 f 就是 format:

System.out.printf("价格:%d 元%n", 99);
```bash

`%n` 表示平台无关的换行符,Windows 上输出回车换行、Linux 上输出换行,比硬写 `\n` 稳妥。

> [!TIP]
> 三选一即可。要把结果存起来、传出去,用 `formatted()`;模板本身是变量或来自配置,用 `String.format`;只是打到控制台看一眼,用 `printf`。

## 常用占位符速查表

| 占位符 | 用途 | 示例输入 | 输出 |
|--------|------|----------|------|
| `%s` | 任意对象,调它的 toString | "abc" | abc |
| `%d` | 十进制整数 | 255 | 255 |
| `%x` / `%X` | 十六进制(小写/大写) | 255 | ff / FF |
| `%o` | 八进制 | 8 | 10 |
| `%f` | 浮点数,默认 6 位小数 | 9.9 | 9.900000 |
| `%e` | 科学计数法 | 12345.6 | 1.234560e+04 |
| `%c` | 单个字符 | 'A' | A |
| `%b` | 布尔值 | true | true |
| `%%` | 输出一个百分号 || % |
| `%n` | 平台相关换行符 || 换行 |

```java
System.out.printf("%s 买了 %d 件,编号 %x,单价 %f%n", "小明", 3, 255, 9.9);
// 小明 买了 3 件,编号 ff,单价 9.900000

%b 有个坑要提醒:它对任意非 null 对象都输出 true,只有 null 才输出 false。所以别拿它去判断一个对象「是不是真的」。

控制小数位数与对齐

浮点数默认打出一长串小数,太丑。用 %.2f 保留两位:

System.out.printf("单价 %.2f 元%n", 9.9);  // 单价 9.90 元
```java

还能指定总宽度和对齐方向。数字表示最小宽度,加负号变左对齐:

```java
System.out.printf("[%8d]%n", 12);   // [      12]  右对齐,宽 8
System.out.printf("[%-8d]%n", 12);  // [12      ]  左对齐
System.out.printf("[%08d]%n", 12);  // [00000012]  用 0 补齐
System.out.printf("[%8.2f]%n", 3.5); // [    3.50] 宽 8、保留 2 位

完整语法是这样拼出来的:百分号、参数序号、标志位、宽度、精度、类型字母。日常记住宽度和精度两个就够,打印对齐的表格全靠它。

System.out.printf("%-10s%8s%n", "商品", "单价");
System.out.printf("%-10s%8.2f%n", "键盘", 199.0);
System.out.printf("%-10s%8.2f%n", "显示器", 1299.5);
```bash

三行输出的列会整整齐齐对上,比手动补空格靠谱得多。

## 按位置填空:索引与上一个参数

变量要重复使用时,用带序号的写法,序号从 1 开始:

```java
String s = "%1$s 你好,%1$s 今天辛苦了".formatted("小明");
// 小明 你好,小明 今天辛苦了

只想复用「上一个参数」,用 %< 更省事,不必数序号:

System.out.printf("%s 得分 %d,%<s 排名 %d%n", "小明", 90, 1);
```bash

这里 `%<s` 表示重复引用刚才那个参数。人名只传一次,模板里用了两遍。

> [!WARNING]
> 占位符类型要和实参类型对上。给 `%d` 传小数会抛 `IllegalFormatConversionException`,参数个数少了会抛 `MissingFormatArgumentException`。这两个都是运行时才炸,编译期不报错,改模板时格外小心。

## 千分位与语言环境

大数字加千分位逗号,加个逗号标志:

```java
System.out.printf("销售额 %,d%n", 1234567); // 销售额 1,234,567

不同国家的分隔符习惯不同,可以显式传 Locale

import java.util.Locale;

System.out.printf(Locale.US, "%,.2f%n", 1234567.5);      // 1,234,567.50
System.out.printf(Locale.GERMANY, "%,.2f%n", 1234567.5); // 1.234.567,50
```bash

德国用点做千分位、逗号做小数点,和中文习惯正好相反。不指定时用的是系统默认语言环境,所以做导出报表这类跨机器运行的功能,最好显式写死一个 Locale,免得换台服务器格式就变了。

## 文本块:多行字符串的正确写法

### 老写法有多难看

Java 15 之前写一段 JSON 或 SQL,只能靠转义和加号:

```java
String json = "{\n" +
              "  \"name\": \"小明\",\n" +
              "  \"age\": 18\n" +
              "}";

引号全要转义,换行符靠手写,加号一列排下去。改一行内容要动三处符号,读的人还得在脑子里把转义还原回去。这种写法属于历史兼容,新代码不推荐。

三个引号搞定

Java 13 预览、Java 15 正式的文本块,用三个双引号包起来,中间原样书写:

String json = """
        {
          "name": "小明",
          "age": 18
        }
        """;
```bash

引号不用转义,换行不用写符号,长什么样就是什么样。缩进也不用担心:编译器会找出所有行(含结尾那行三引号)里最靠左的位置,把公共缩进整体删掉,所以上面这段的实际内容顶格开始。

结尾的三引号放在哪一列,直接决定了公共缩进的基准。想让内容整体带缩进,把结尾三引号往左移即可。

### 文本块加格式化

文本块和 `formatted()` 是绝配:

```java
String name = "小明";
int age = 18;
String json = """
        {
          "name": "%s",
          "age": %d
        }
        """.formatted(name, age);

模板长什么样一目了然,变量位置清清楚楚。写 SQL、HTML 片段、多行提示文案,这就是 Java 25 基线下的标准写法。

Note

文本块默认每行结尾都有换行符。行尾加一个反斜杠可以取消该行换行(把长行折行书写),加 \s 可以保留一个尾部空格——尾部空白默认会被删掉。

日期也能塞进占位符

格式化同样认识日期时间类型,用字母 t 开头的一族占位符:

import java.time.LocalDate;

LocalDate d = LocalDate.of(2026, 8, 5);
System.out.printf("%tF%n", d);  // 2026-08-05,标准日期格式
System.out.printf("%tY 年 %<tm 月 %<td 日%n", d); // 2026 年 08 月 05 日
```bash

5 行用了两次 `%<`,同一个日期对象只传一遍。后面的字母决定取哪一部分:Y 是四位年、m 是月、d 是日、H 是时、M 是分、S 是秒。

不过日期格式化更推荐专门的 `DateTimeFormatter`,模式串写起来直观得多,也能处理时区。占位符这套适合临时打印调试,正式输出走日期章节讲的那一套。

## 常见疑问

**问:格式化和字符串拼接,性能差多少?**

格式化要解析模板字符串,比直接拼接慢一些。日志、报表这类每次调用几微秒无所谓的地方随便用;如果是每秒百万次的热点循环,用 StringBuilder 更快。别为了性能牺牲可读性,先测了再说。

**问:文本块里能写三个连续的双引号吗?**

能,把其中一个转义成 `\"` 就行。这种情况很少见,遇到再查。

**问:`String.format` 和 `MessageFormat` 该用哪个?**

日常格式化用 `String.format` 系列。`MessageFormat` 用大括号加序号做占位,主要服务于国际化资源文件,还能处理单复数规则,属于专门场景。

## 小结

格式化把模板和数据分开,代码更干净。三个入口记牢:`formatted()` 最现代、`String.format` 留着结果用、`printf` 直接打印。占位符里 `%s` 通吃、`%d` 整数、`%f` 浮点,`%.2f` 控小数位、宽度控对齐、逗号加千分位,类型必须对得上否则运行时报错。多行字符串一律用文本块,配合 `formatted()` 写 JSON 和 SQL 最舒服。