1. 概述
在本教程中,我们将介绍 Java String 转换为 BigDecimal 的多种方法,以及如何解析格式化的字符串。
2.BigDecimal 简介
BigDecimal 表示不可变的、任意精度的有符号十进制数 。它由两部分组成:
- 非标度值(Unscaled value) – 任意精度整数
- 整数标度(Scale) – 一个 32 位整数,表示小数点右侧的位数
例如, BigDecimal 3.14 的非标度值是 314,小数位数为 2。
如果为零或正数,则小数位数是小数点右侧的位数。
如果为负,则该数字的非标度值乘以 10 的缩放负次方。因此, BigDecimal 表示的数字的值为 (Unscaled value × 10-Scale) 。
BigDecimal 主要用于高精度计算场景,例如金融交易。
有多种方法可以将 String 转换为 BigDecimal :
- 使用 BigDecimal(String) 构造函数
- 使用 BigDecimal.valueOf() 方法
- 使用 DecimalFormat.parse() 方法
下面我们逐一讨论。
3. 方法一、BigDecimal(String)
最简单的方法,是使用 BigDecimal(String) 构造函数
BigDecimal bigDecimal = new BigDecimal("123");
assertEquals(new BigDecimal(123), bigDecimal);
4. 方法二、BigDecimal.valueOf()
使用 BigDecimal.valueOf(double) 方法将 String 转换为 BigDecimal 。
首先需要将 String 转换为 Double 类型,然后再将 Double 转换为 BigDecimal :
BigDecimal bigDecimal = BigDecimal.valueOf(Double.valueOf("123.42"));
assertEquals(new BigDecimal(123.42).setScale(2, BigDecimal.ROUND_HALF_UP), bigDecimal);
编者注:这种方式不推荐,属于画蛇添足,因为 BigDecimal.valueOf() 内部使用 Double.toString() 方法,将浮点类型的值转换为字符串,然后调用方法一的BigDecimal构造函数
必须注意的是,某些浮点数无法使用 Double 值精确表示。这是因为 Double 类型的浮点数在内存中表示。事实上,该数字以尽可能接近输入的 Double 数字的有理形式表示。结果,一些浮点数变得不准确。
5. 方法三、DecimalFormat.parse()
当字符串格式复杂,包含非数字符号时,我们可以使用 DecimalFormat。
示例一,我们解析字符串 "10,692,467,440,017.111":
BigDecimal bigDecimal = new BigDecimal(10692467440017.111).setScale(3, BigDecimal.ROUND_HALF_UP);
// 设置格式
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setGroupingSeparator(',');
symbols.setDecimalSeparator('.');
String pattern = "#,##0.0#";
DecimalFormat decimalFormat = new DecimalFormat(pattern, symbols);
decimalFormat.setParseBigDecimal(true);
// 解析字符串
BigDecimal parsedStringValue = (BigDecimal) decimalFormat.parse("10,692,467,440,017.111");
// 验证结果是否正确
assertEquals(bigDecimal, parsedStringValue);
DecimalFormat.parse 方法返回的是 Number 类型,需要设置 setParseBigDecimal(true)
将其转换为 BigDecimal 类型。
示例二,解析带有百分号的字符串,例如解析 “2%” 为 0.02:
// 设置格式
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
String pattern = "#.##%";
DecimalFormat decimalFormat = new DecimalFormat(pattern, symbols);
decimalFormat.setParseBigDecimal(true);
// 解析字符串
BigDecimal parsedStringValue = (BigDecimal) decimalFormat.parse("2%");
System.out.println(parsedStringValue); // 输出 0.02
6. 异常处理
空指针异常 - NullPointerException :
@Test(expected = NullPointerException.class)
public void givenNullString_WhenBigDecimalObjectWithStringParameter_ThenNullPointerExceptionIsThrown() {
String bigDecimal = null;
new BigDecimal(bigDecimal);
}
@Test(expected = NullPointerException.class)
public void givenNullString_WhenValueOfDoubleFromString_ThenNullPointerExceptionIsThrown() {
BigDecimal.valueOf(Double.valueOf(null));
}
@Test(expected = NullPointerException.class)
public void givenNullString_WhenDecimalFormatOfString_ThenNullPointerExceptionIsThrown()
throws ParseException {
new DecimalFormat("#").parse(null);
}
无效字符 - NumberFormatException:
@Test(expected = NumberFormatException.class)
public void givenInalidString_WhenBigDecimalObjectWithStringParameter_ThenNumberFormatExceptionIsThrown() {
new BigDecimal("&");
}
@Test(expected = NumberFormatException.class)
public void givenInalidString_WhenValueOfDoubleFromString_ThenNumberFormatExceptionIsThrown() {
BigDecimal.valueOf(Double.valueOf("&"));
}
解析异常 - ParseException:
@Test(expected = ParseException.class)
public void givenInalidString_WhenDecimalFormatOfString_ThenNumberFormatExceptionIsThrown()
throws ParseException {
new DecimalFormat("#").parse("&");
}
7、总结
本文我们介绍了多种方法将 String 转换为 BigDecimal。一般来说,我们建议使用 new BigDecimal(String) 。
最后,本文中使用的代码可以在 GitHub 上找到。