0Pricing
Java Academy · 课时

NumberFormat 与 printf

使用 NumberFormat、DecimalFormat 和 printf 格式模式格式化要显示的数字

NumberFormat 与 printf 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

NumberFormat 与 printf

Java 提供了丰富的数字格式化接口:NumberFormat 用于根据区域设置格式化货币和百分比,DecimalFormat 用于自定义模式,printf 和 String.format 用于 C 风格格式化。

String.format 基础

String.format() 使用格式说明符构建字符串。常用说明符包括:%d(整数)、%f(浮点数)、%s(字符串)、%n(换行)。

String name = "Alice";
int score = 95;
double avg = 87.567;

String msg = String.format(
    "Player: %s | Score: %d | Average: %.2f", name, score, avg);
System.out.println(msg);
// Player: Alice | Score: 95 | Average: 87.57

// printf is equivalent — formats directly to output
System.out.printf("%-10s %5d %8.2f%n", name, score, avg);
// Alice          95    87.57

宽度、填充与对齐

格式说明符支持宽度和对齐标志:%10d(在 10 个字符宽度内右对齐)、%-10d(左对齐)、%010d(用零填充)。

// Table layout with padding
System.out.printf("%-20s %10s %10s%n", "Product", "Qty", "Price");
System.out.printf("%-20s %10d %10.2f%n", "Java Book", 3, 49.99);
System.out.printf("%-20s %10d %10.2f%n", "USB Hub", 1, 24.95);
System.out.printf("%-20s %10d %10.2f%n", "Mechanical Keyboard", 2, 129.00);

// Zero-padding for order IDs
int orderId = 42;
System.out.printf("Order: ORD-%08d%n", orderId); // Order: ORD-00000042

使用 NumberFormat 格式化货币

NumberFormat.getCurrencyInstance(Locale) 会根据指定的区域设置,将数字格式化为包含正确货币符号、分隔符和小数位数的货币字符串。

import java.text.*;
import java.util.*;

NumberFormat usd = NumberFormat.getCurrencyInstance(Locale.US);
NumberFormat eur = NumberFormat.getCurrencyInstance(Locale.GERMANY);
NumberFormat gbp = NumberFormat.getCurrencyInstance(Locale.UK);

double amount = 1234567.89;
System.out.println(usd.format(amount)); // $1,234,567.89
System.out.println(eur.format(amount)); // 1.234.567,89 EUR
System.out.println(gbp.format(amount)); // GBP1,234,567.89

使用 NumberFormat 格式化百分比

NumberFormat.getPercentInstance() 会将小数格式化为百分比字符串。请传入 0 到 1 之间的值。

import java.text.*;
import java.util.*;

NumberFormat pct = NumberFormat.getPercentInstance(Locale.US);
pct.setMaximumFractionDigits(1);

System.out.println(pct.format(0.75));     // 75%
System.out.println(pct.format(0.1234));   // 12.3%
System.out.println(pct.format(1.0));      // 100%

// Conversion rate in e-commerce
double convRate = 3_456.0 / 42_000.0;
System.out.println("Conversion: " + pct.format(convRate)); // 8.2%

使用 DecimalFormat 自定义模式

DecimalFormat 使用模式字符串,其中 # 表示可选数字,0 表示必需数字。

import java.text.*;

DecimalFormat df1 = new DecimalFormat("#,###.00");
System.out.println(df1.format(1234567.5));  // 1,234,567.50

DecimalFormat df2 = new DecimalFormat("000.0");
System.out.println(df2.format(7.5));  // 007.5

DecimalFormat df3 = new DecimalFormat("0.00E0");
System.out.println(df3.format(0.000123)); // 1.23E-4

// Scientific notation for large values
DecimalFormat sci = new DecimalFormat("0.000E0");
System.out.println(sci.format(123456789)); // 1.235E8

从字符串解析数字

NumberFormat 还可以将按区域设置格式化的字符串解析回数字。这对于读取不同区域设置下的用户输入至关重要。

import java.text.*;
import java.util.*;

NumberFormat nf = NumberFormat.getInstance(Locale.GERMANY);
try {
    // German uses comma as decimal separator
    Number parsed = nf.parse("1.234,56");
    System.out.println(parsed.doubleValue()); // 1234.56

    // Parse US currency string
    NumberFormat usd = NumberFormat.getCurrencyInstance(Locale.US);
    Number amount = usd.parse("$1,234.56");
    System.out.println(amount.doubleValue()); // 1234.56
} catch (ParseException e) {
    System.out.println("Parse error: " + e.getMessage());
}

格式化字符串(Java 15+)

Java 15+ 添加了 String.formatted(),作为 String.format() 的实例方法替代方案;它适用于方法链和流处理管道。

record Product(String name, double price, int stock) {}

var products = List.of(
    new Product("Laptop", 999.0, 5),
    new Product("Mouse",  29.99, 42),
    new Product("Monitor", 349.0, 8)
);

products.stream()
    .map(p -> "%-15s $%8.2f  [stock: %d]"
        .formatted(p.name(), p.price(), p.stock()))
    .forEach(System.out::println);
// Laptop          $  999.00  [stock: 5]
// Mouse           $   29.99  [stock: 42]
// Monitor         $  349.00  [stock: 8]

数字分组与区域设置

数字分组(千位分隔符)会因区域设置而异。面向用户的输出应始终使用 NumberFormat,而不要将逗号硬编码。

import java.text.*;
import java.util.*;

long users = 1_234_567;

for (Locale locale : new Locale[]{Locale.US, Locale.FRANCE, Locale.GERMANY}) {
    NumberFormat nf = NumberFormat.getIntegerInstance(locale);
    System.out.printf("%-10s: %s%n", locale, nf.format(users));
}
// en_US     : 1,234,567
// fr_FR     : 1 234 567
// de_DE     : 1.234.567

发票生成示例

综合运用这些内容:生成格式正确的发票打印输出,包括货币、百分比和表格对齐。

import java.text.*;
import java.util.*;

NumberFormat curr = NumberFormat.getCurrencyInstance(Locale.US);
NumberFormat pct  = NumberFormat.getPercentInstance();
pct.setMaximumFractionDigits(0);

double subtotal = 1259.97;
double discount = 0.10;
double discountAmt = subtotal * discount;
double taxRate = 0.08;
double taxAmt = (subtotal - discountAmt) * taxRate;
double total = subtotal - discountAmt + taxAmt;

System.out.println("=== INVOICE ===");
System.out.printf("%-20s %15s%n", "Subtotal",       curr.format(subtotal));
System.out.printf("%-20s %15s%n", "Discount (" + pct.format(discount) + ")",
    "-" + curr.format(discountAmt));
System.out.printf("%-20s %15s%n", "Tax (" + pct.format(taxRate) + ")",
    curr.format(taxAmt));
System.out.printf("%-20s %15s%n", "TOTAL", curr.format(total));

常见陷阱

请注意以下常见的格式化错误:

  • 使用 String.format 时类型说明符错误(例如对 double 使用 %d)会抛出 IllegalFormatConversionException
  • 特定区域设置的格式化程序在不同机器上可能产生不同的输出
  • NumberFormat 实例不是线程安全的,请为每个线程创建一个实例,或使用 ThreadLocal
// Wrong specifier
try {
    String.format("%d", 3.14); // IllegalFormatConversionException
} catch (java.util.IllegalFormatConversionException e) {
    System.out.println("Wrong format specifier!");
}

// Thread-safe pattern using ThreadLocal
ThreadLocal<NumberFormat> localFmt = ThreadLocal
    .withInitial(() -> NumberFormat.getCurrencyInstance(Locale.US));
// each thread gets its own NumberFormat instance

快速检查

String.format("%08.2f", 3.5) 会产生什么结果?

总结:NumberFormat 与 printf

要点:

  • String.format / printf 使用格式说明符:%d、%f、%s、%.2f
  • 宽度和对齐标志:%10d(右对齐)、%-10d(左对齐)、%010d(用零填充)
  • 使用 NumberFormat.getCurrencyInstance() 根据区域设置显示货币
  • 使用 NumberFormat.getPercentInstance() 输出百分比
  • DecimalFormat 使用 #(可选)和 0(必需)数字模式
  • NumberFormat 还可以将按区域设置格式化的字符串解析回数字

常见问题解答

「NumberFormat 与 printf」课时是免费的吗?

是的 — 「NumberFormat 与 printf」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「NumberFormat 与 printf」这节课中我会学到什么?

使用 NumberFormat、DecimalFormat 和 printf 格式模式格式化要显示的数字 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「NumberFormat 与 printf」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Math 类基础
  2. 整数运算与溢出
  3. 使用 BigDecimal 进行财务计算
  4. NumberFormat 与 printf
← 返回 Java Academy