1. 概述
在这个教程中,我们将探讨Java中截断double
到两位小数的各种方法。我们将看到将结果转换为String
的方法,以及返回Number
对象的选项。
2. 使用Math.floor()
和Math.ceil()
四舍五入
我们将首先研究使用Math
类去除多余小数位的方法。要将正数截断到两位小数,我们首先将double
乘以100,将所有保留的小数位移动到小数点之前。接着,使用Math.floor()
向下取整,移除小数点后的所有部分。最后,除以100来撤销之前的乘法:
@Test
void givenADouble_whenUsingMath_truncateToTwoDecimalPlaces(){
double positive = 1.55555555;
double truncated = Math.floor(positive * 100) / 100;
assertEquals("1.55", String.valueOf(truncated));
double negative = -1.55555555;
double negativeTruncated = Math.ceil(negative * 100) / 100;
assertEquals("-1.55", String.valueOf(negativeTruncated));
}
对于负数,过程几乎相同,但我们会用Math.ceil()
向上取整。如果我们希望自动检测double
是正还是负,并根据需要使用正确的方法,可以添加额外的代码。
如果需要保留更多或更少的小数位,只需在乘法和除法中增加或减少零。例如,为了保留三位小数,我们将乘以和除以1000。这种方法在我们需要将double
保持为double
,而不是将其转换为String
时很有用。
3. 使用String.format()
接下来,我们将看看一些设计用于显示而非计算的目的方法。这些方法会返回String
,但我们始终可以将结果转换回double
,如果需要的话。String.format()
方法接受两个参数:我们想要应用的格式和格式字符串中的引用参数。为了截断到两位小数,我们将使用格式字符串"%.2f"
:
@Test
void givenADouble_whenUsingStringFormat_truncateToTwoDecimalPlaces() {
double positive = 1.55555555;
String truncated = String.format("%.2f", positive);
assertEquals("1.56", truncated);
double negative = -1.55555555;
String negativeTruncated = String.format("%.2f", negative);
assertEquals("-1.56", negativeTruncated);
}
格式字符串末尾的f
指示格式化器生成小数格式,而.2
表示我们希望小数点后有两位。我们可以根据需要调整这个值来截断到所需的位数。测试显示结果实际上进行了向上舍入,而不是截断,因此这可能不适合我们的需求。
4. 使用NumberFormat
创建String
NumberFormat
是一个抽象类,旨在让我们格式化任何数字。由于它是一个抽象类,我们需要先使用getNumberInstance()
获取一个可以使用的对象。注意,如果没有特别指定,它将使用默认的本地化。然后,我们可以使用setMaximumFractionDigits()
指定我们想要的小数位数。最后,因为我们要进行截断而不是四舍五入,所以我们使用setRoundingMode()
并传入RoundingMode.DOWN
参数:
@Test
public void givenADouble_whenUsingNumberFormat_truncateToTwoDecimalPlaces(){
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(2);
nf.setRoundingMode(RoundingMode.DOWN);
double value = 1.55555555;
String truncated = nf.format(value);
assertEquals("1.55", truncated);
double negativeValue = -1.55555555;
String negativeTruncated = nf.format(negativeValue);
assertEquals("-1.55", negativeTruncated);
}
有了NumberFormat
的设置,我们只需调用format()
方法并传入我们的double
即可。在上述测试中,我们可以看到它对正负数处理得同样好。
5. 使用DecimalFormat
创建String
DecimalFormat
是NumberFormat
的一个子类,专为小数设计。它是具体的类,所以可以直接创建一个实例,通过构造函数传递我们想要的模式。这里我们将传递“#.##.”,小数点后的数量号表示要保留多少位:
@Test
public void givenADouble_whenUsingDecimalFormat_truncateToTwoDecimalPlaces(){
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.DOWN);
double value = 1.55555555;
String truncated = df.format(value);
assertEquals("1.55", truncated);
double negativeValue = -1.55555555;
String negativeTruncated = df.format(negativeValue);
assertEquals("-1.55", negativeTruncated);
}
与之前的NumberFormat
一样,我们也指定了RoundingMode.DOWN
的使用。再次看到这个解决方案对正负数处理得很好,使其很有用。
6. 使用BigDecimal
获得最优精度
Java的BigDecimal
类最适合直接处理小数位的截断,同时保持结果为我们可以进行进一步计算的数字。如果可能,使用BigDecimal
代替double
可能是最佳选择。我们可以将double
值传递给构造函数,同时直接告诉它保留两位小数并向下取整:
@Test
void givenADouble_whenUsingBigDecimal_truncateToTwoDecimalPlaces(){
BigDecimal positive = new BigDecimal(2.555555).setScale(2, RoundingMode.DOWN);
BigDecimal negative = new BigDecimal(-2.555555).setScale(2, RoundingMode.DOWN);
assertEquals("2.55", positive.toString());
assertEquals("-2.55", negative.toString());
}
我们在测试中将结果转换为String
以视觉上清晰地展示结果。然而,如果我们想继续使用截断后的输出进行进一步计算,我们可以这样做。
7. 总结
我们已经讨论了Java中截断double
的五种不同方法。我们了解到,String.format()
,NumberFormat
,和DecimalFormat
在用于展示目的时可用,因为它们会输出String
。当然,我们总是可以使用Double.parseDouble()
将String
转换回double
。或者,我们可以使用Math
类或BigDecimal
来保持截断后的数值作为可以进行进一步计算的数字。