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 上找到。