在 Java 中,将 double 类型保留两位小数有多种方法,每种方法都有其适用场景和优缺点。

(图片来源网络,侵删)
下面我将详细介绍几种最常用和最推荐的方法,并提供代码示例。
使用 DecimalFormat (最推荐,用于格式化输出)
DecimalFormat 是 java.text 包中的一个类,专门用于格式化数字,它非常适合用于将数字格式化为字符串,以便显示或打印。
优点:
- 非常灵活,可以轻松控制数字的格式(如千位分隔符、前缀、后缀等)。
- 专门为格式化显示而设计,代码可读性高。
缺点:

(图片来源网络,侵删)
- 返回的是一个
String类型,如果后续需要进行数学计算,需要重新转换回double或BigDecimal,可能会引入精度问题。
示例代码:
import java.text.DecimalFormat;
public class DecimalFormatExample {
public static void main(String[] args) {
double number = 123.456789;
// 1. 创建 DecimalFormat 对象,模式 "0.00" 表示两位小数
// "0" 表示一个数字位,如果不足则补0
// "#" 表示一个数字位,如果不足则不显示
DecimalFormat df = new DecimalFormat("0.00");
// 2. 格式化数字
String formattedNumber = df.format(number);
System.out.println("原始数字: " + number);
System.out.println("格式化后: " + formattedNumber); // 输出: 123.46 (四舍五入)
// --- 其他模式示例 ---
DecimalFormat df2 = new DecimalFormat("#.##"); // 如果小数部分为0,则不显示小数点
System.out.println("模式 #.##: " + df2.format(123.0)); // 输出: 123
System.out.println("模式 #.##: " + df2.format(123.45)); // 输出: 123.45
DecimalFormat df3 = new DecimalFormat(",###.00"); // 添加千位分隔符
System.out.println("模式 ,###.00: " + df3.format(12345.6789)); // 输出: 12,345.68
}
}
使用 String.format() 或 System.out.printf() (简洁,用于格式化输出)
这是 Java 提供的一种非常简洁的格式化字符串的方式,类似于 C 语言中的 printf。
优点:
- 语法简洁,一行代码即可完成。
- 与
System.out.println结合使用非常方便。
缺点:

(图片来源网络,侵删)
- 同样返回
String类型,不适用于后续计算。
示例代码:
public class StringFormatExample {
public static void main(String[] args) {
double number = 123.456789;
// 使用 String.format()
// %.2f 表示格式化为一个浮点数,并保留两位小数
String formattedNumber = String.format("%.2f", number);
System.out.println("原始数字: " + number);
System.out.println("格式化后: " + formattedNumber); // 输出: 123.46
// 使用 System.out.printf() 直接打印
System.out.println("直接打印格式化结果:");
System.out.printf("%.2f%n", number); // %n 是平台无关的换行符
}
}
使用 BigDecimal (最精确,用于计算和存储)
如果你需要对保留两位小数后的结果进行精确的数学运算(例如财务计算),BigDecimal 是唯一推荐的方案。double 和 float 本身就存在精度问题,直接使用它们进行计算可能会导致错误。
优点:
- 可以精确表示小数,避免浮点数精度问题。
- 提供了精确的舍入控制(如
RoundingMode.HALF_UP)。
缺点:
- 使用起来比前两种方法稍微复杂一些。
- 创建
BigDecimal对象时,千万不要使用double作为构造参数,因为传入的double本身就是不精确的,应该使用String作为构造参数。
示例代码:
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalExample {
public static void main(String[] args) {
double number = 123.456789;
// 1. 使用 String 构造 BigDecimal,保证精度
BigDecimal bd = new BigDecimal(String.valueOf(number));
// 2. 设置保留两位小数,并指定舍入模式
// RoundingMode.HALF_UP 是最常用的四舍五入模式
BigDecimal roundedBD = bd.setScale(2, RoundingMode.HALF_UP);
// 3. 转换回 double (如果后续需要用 double 类型)
double result = roundedBD.doubleValue();
System.out.println("原始数字: " + number);
System.out.println("BigDecimal 格式化后: " + roundedBD); // 输出: 123.46
System.out.println("转换回 double: " + result);
// --- 精确计算示例 ---
double a = 0.1;
double b = 0.2;
System.out.println("\n错误示范 (double 直接相加): " + (a + b)); // 输出: 0.30000000000000004
BigDecimal bdA = new BigDecimal("0.1");
BigDecimal bdB = new BigDecimal("0.2");
BigDecimal preciseSum = bdA.add(bdB);
System.out.println("正确示范 (BigDecimal 相加): " + preciseSum); // 输出: 0.3
}
}
使用 Math.round() (简单,但不推荐用于商业计算)
这种方法通过将数字乘以100,四舍五入,再除以100来实现,看起来简单直接,但存在一个严重的问题。
示例代码:
public class MathRoundExample {
public static void main(String[] args) {
double number = 123.456;
// 1. 乘以100
double temp = number * 100; // 12345.6
// 2. 四舍五入
long roundedTemp = Math.round(temp); // 12346
// 3. 除以100
double result = roundedTemp / 100.0; // 123.46
System.out.println("原始数字: " + number);
System.out.println("Math.round 处理后: " + result);
// --- 潜在问题 ---
// 由于 double 的精度问题,当数字很大或很小时,可能会出错
double problematicNumber = 125.125;
double problematicResult = Math.round(problematicNumber * 100) / 100.0;
System.out.println("\n问题数字: " + problematicNumber);
System.out.println("Math.round 处理后 (错误): " + problematicResult); // 可能输出 125.12 而不是 125.13
}
}
为什么不推荐?
- 精度问题:
double的乘法和除法本身就可能引入新的舍入误差,导致最终结果不准确。 - 类型转换:在
long roundedTemp = Math.round(temp);这一步,temp超出了long的表示范围(约2 x 10^18),就会发生溢出,导致错误结果。
总结与选择建议
| 方法 | 返回类型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
DecimalFormat |
String |
格式化输出到UI、日志、文件 | 灵活,可读性好 | 返回String,不用于计算 |
String.format() |
String |
快速格式化输出 | 语法简洁,方便 | 返回String,不用于计算 |
BigDecimal |
BigDecimal |
精确的数学计算、财务、存储 | 精度最高,绝对准确 | 使用稍复杂,需注意构造方式 |
Math.round() |
double |
简单的数值处理(不推荐) | 代码简单 | 有精度风险,可能溢出 |
如何选择?
-
如果你的目的是显示或打印:
- 首选
String.format(),因为它最简洁。 - 如果需要更复杂的格式(如千位分隔符),使用
DecimalFormat。
- 首选
-
如果你的目的是进行精确计算(尤其是金钱):
- 必须使用
BigDecimal,这是行业标准,能避免所有潜在的精度问题。
- 必须使用
-
尽量避免使用
Math.round()来处理double的保留小数问题,除非你非常清楚其潜在风险,并且处理的数值范围有限。
