1. 概述

String.format() 方法根据预设规则格式化字符串并返回结果。本文将深入解析该方法的语法、基础与高级用法、常见异常及最佳实践。

2. 方法语法

String.format() 提供两种重载形式:

public static String format (String format, Object... args)
public static String format (Locale l, String format, Object... args)

参数说明:

  • format(String类型):格式字符串
  • args(Object类型):格式字符串中引用的参数
  • l(Locale类型):指定格式化使用的区域设置

⚠️ 关键规则

  1. args 数量必须与格式说明符数量匹配,多余参数会被忽略
  2. 默认情况下,参数顺序需与格式说明符顺序严格对应
  3. 支持通过索引引用参数(如 %1$s 引用第一个参数),实现参数重排序或复用

示例:使用区域设置

String result = String.format(Locale.FRANCE, "Value: %.2f", 1234.5678);

3. 格式说明符

格式说明符语法因数据类型而异,但必须包含转换符。常见转换符:

转换符 说明 示例输入 输出
%b 布尔值 true "true"
%c 单个字符 'A' "A"
%d 十进制整数 255 "255"
%x 十六进制整数 255 "ff"
%f 浮点数 123.456 "123.456"
%e 科学计数法 123.456 "1.234560e+02"

⚠️ null值处理%s%S 转换符遇到 null 参数会输出 "null"

4. 基础用法

通过JUnit测试演示常见用法:

@Test
public void whenFormat_thenCorrect() {
    String value = "Baeldung";
    String formatted = String.format("Welcome to %s!", value);
    assertEquals("Welcome to Baeldung!", formatted);

    boolean boolValue = true;
    String formattedBool = String.format("Boolean: %b", boolValue);
    assertEquals("Boolean: true", formattedBool);

    char charValue = 'A';
    String formattedChar = String.format("Character: %c", charValue);
    assertEquals("Character: A", formattedChar);

    int intValue = 255;
    String formattedInt = String.format("Decimal: %d", intValue);
    assertEquals("Decimal: 255", formattedInt);

    String formattedHex = String.format("Hex: %x", intValue);
    assertEquals("Hex: ff", formattedHex);

    double floatValue = 123.456789;
    String formattedFloat = String.format("Float: %.2f", floatValue);
    assertEquals("Float: 123.46", formattedFloat);

    String formattedExponential = String.format("Exponential: %e", floatValue);
    assertEquals("Exponential: 1.234568e+02", formattedExponential);
}

多格式符组合

String multipleFormat = String.format(
  "Boolean: %b, Character: %c, Decimal: %d, Hex: %x, Float: %.2f, Exponential: %e", 
  boolValue, charValue, intValue, intValue, floatValue, floatValue
);

assertEquals("Boolean: true, Character: A, Decimal: 255, Hex: ff, Float: 123.46, Exponential: 1.234568e+02", 
  multipleFormat);

5. 异常处理

5.1. 不兼容的标志

当格式符使用不兼容标志时抛出 FormatFlagsConversionMismatchException

@Test
public void whenIncompatibleFlags_thenFormatFlagsConversionMismatchExceptionThrown() {
    assertThrows(FormatFlagsConversionMismatchException.class, () -> {
        String formatted = String.format("%+s", "Baeldung"); // 字符串不支持+标志
    });
}

5.2. 精度类型不匹配

对不支持精度的类型使用精度时抛出 IllegalFormatPrecisionException

@Test
public void whenInvalidPrecisionForType_thenIllegalFormatPrecisionExceptionThrown() {
    assertThrows(IllegalFormatPrecisionException.class, () -> {
        String formatted = String.format("%.2d", 123); // 整数不支持精度
    });
}

5.3. 参数数量不匹配

格式符数量超过参数数量时抛出 MissingFormatArgumentException

@Test
public void whenMissingFormatArgument_thenMissingFormatArgumentExceptionThrown() {
    assertThrows(MissingFormatArgumentException.class, () -> {
        String formatted = String.format("Welcome to %s and %s!", "Baeldung"); // 缺少第二个参数
    });
}

6. 整数前补零

6.1. 基础实现

补零工具方法:

private String padIntegerWithZeros(int number, int width) {
    return String.format("%0" + width + "d", number);
}

格式符解析:

  • %:格式符起始符
  • 0:用0补位
  • <width>:最小输出宽度
  • d:十进制整数转换

6.2. 正负数处理

@Test
public void givenAnInteger_whenPaddingWithZeros_thanIntegerGetsPadded() {
    assertEquals("00000001", padIntegerWithZeros(1, 8));
    assertEquals("-0000001", padIntegerWithZeros(-1, 8)); // 负号保留,补零在符号后
}

6.3. 常见坑点

⚠️ 类型转换异常:错误使用转换符会导致 IllegalFormatConversionException

  • ❌ 错误示例:String.format("%s", 123)(整数用字符串格式符)
  • ✅ 正确做法:始终使用 %d 处理整数

7. 区域化格式化

7.1. 数字格式

不同区域的千分位/小数点分隔符:

@Test
public void whenNumberFormatWithLocales_thenCorrect() {
    String frenchFormatted = String.format(Locale.FRANCE, "%,f", 1234567.89);
    assertEquals("1 234 567,890000", frenchFormatted); // 法国用空格作千分位
    String germanFormatted = String.format(Locale.GERMANY, "%,.2f", 1234567.89);
    assertEquals("1.234.567,89", germanFormatted); // 德国用点作千分位
}

7.2. 日期格式

@Test
public void whenDateFormatWithLocales_thenCorrect() {
    LocalDate date = LocalDate.of(2023, 9, 30);

    DateTimeFormatter usFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy", Locale.US);
    String usFormatted = date.format(usFormatter);
    assertEquals("09/30/2023", usFormatted);

    DateTimeFormatter germanFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale.GERMANY);
    String germanFormatted = date.format(germanFormatter);
    assertEquals("30.09.2023", germanFormatted);
}

7.3. 货币格式

@Test
public void whenCurrencyFormatWithLocales_thenCorrect() {
    NumberFormat usCurrencyFormat = NumberFormat.getCurrencyInstance(Locale.US);
    String usFormatted = usCurrencyFormat.format(1000);
    assertEquals("$1,000.00", usFormatted);

    NumberFormat frenchCurrencyFormat = NumberFormat.getCurrencyInstance(Locale.FRANCE);
    String frenchFormatted = frenchCurrencyFormat.format(1000);
    assertEquals("1 000,00 €", frenchFormatted); // 法国货币符号在后
}

8. 总结

本文系统介绍了 String.format() 的核心用法:

  • 基础语法与格式符规则
  • 参数绑定与区域化处理
  • 常见异常场景与解决方案
  • 实用技巧(如补零、多类型组合)

完整示例代码见 GitHub项目。掌握这些技巧能显著提升字符串处理效率,避免常见的格式化陷阱。