Resumen de BigDecimal pisando el pit

Inicializar BigDecimal con tipo String

La clase API BigDecimal proporcionada por Java en el paquete java.math se usa para realizar operaciones precisas en números con más de 16 dígitos significativos. Al inicializar bigDecimal, no use el valor de tipo double o float para pasar al constructor. La comparación muestra que test2 seguirá teniendo problemas de precisión, pero al crear un objeto BigDecimal, si el parámetro es una cadena, no habrá precisión. problema, por lo que el resumen es el siguiente

//使用String构造
BigDecimal b1 = new BigDecimal("0.1");
//或者是:
BigDecimal b1 = BigDecimal.valueOf(0.1);
//点开valueOf的源码,可以看到在源码中也是用new BigDecimal(String);返回一个BigDecimal对象的
//源码如下:
public static BigDecimal valueOf(double val) {
    // Reminder: a zero double returns '0.0', so we cannot fastpath
    // to use the constant ZERO.  This might be important enough to
    // justify a factory approach, a cache, or a few private
    // constants, later.
    return new BigDecimal(Double.toString(val));
}
复制代码

No use iguales para la comparación al hacer comparaciones numéricas BigDecimal

Usar iguales para comparar comparará el tamaño del valor y el tamaño de la precisión, es decir, 0.00 y 0.000 no son iguales, use compareTo() para comparar.

Al realizar cálculos, es necesario asegurarse de que el valor que participa en el cálculo no puede ser nulo

Al usar el tipo BigDecimal para el cálculo, al sumar, restar, multiplicar, dividir y comparar tamaños, asegúrese de que los dos valores involucrados en el cálculo no puedan estar vacíos, de lo contrario, se lanzará una excepción java.lang.NullPointerException.

Por ejemplo, los siguientes dos fragmentos de código generarán una excepción:

BigDecimal number1 = null;
BigDecimal number2 = new BigDecimal("11.12");

BigDecimal number3 = number1.add(number2);
System.out.println("number1 add number2 = " + number3);

BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = null;

BigDecimal number3 = number1.add(number2);
System.out.println("number1 add number2 = " + number3);
复制代码

La excepción lanzada es como se muestra a continuación:

Tenga cuidado con los decimales de bucle infinito y los divisores no pueden ser 0 cuando se usan dividemétodos

Cuando BigDecimalel dividemétodo se usa una vez, se lanza una excepción java.lang.ArithmeticExceptiony el código de error es el siguiente:

// 含税金额
BigDecimal inclusiveTaxAmount = new BigDecimal("1000");
// 税率
BigDecimal taxRate = new BigDecimal("0.13");
// 不含税金额 = 含税金额 / (1+税率)
BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate));

System.out.println(exclusiveTaxAmount);
复制代码

El tiempo de ejecución arroja la siguiente excepción:

El motivo del error es que no puede ser divisible, lo que da como resultado un bucle infinito de decimales:

La solución es especificar el modo de redondeo hacia abajo, como nuestro modo de redondeo más común:

// 不含税金额 = 含税金额 / (1+税率)
BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate),RoundingMode.HALF_UP);
复制代码

En este punto, no se informa ningún error y el resultado es: 885

Pero mi requisito aquí es mantener 2 decimales y redondear hacia arriba, por lo que el código debería ser el siguiente:

// 不含税金额 = 含税金额 / (1+税率)
BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate), 2, RoundingMode.HALF_UP);
复制代码

La salida en este momento es: 884.96

BigDecimal to String, problema de notación científica

Conclusión: para convertir BigDecimal a String, se recomienda usar toPlainString() en lugar de toString()

Tal vez lo escribiste así:

BigDecimal amount = new BigDecimal("3450.67");
System.out.println(amount.toString());
复制代码

Resultado de salida: 3450.67

En la mayoría de los casos, no hay problema con este uso, pero en algunos escenarios, es fácil pisar el foso, como los siguientes tres ejemplos:

System.out.println( new BigDecimal("0.000000000000").toString());
//输出结果:0E-12

BigDecimal bigDecimal = new BigDecimal("1E+11");
System.out.println(bigDecimal.toString());
//输出结果:1E+11
复制代码

还有个更为常用的场景:抹零,也容易踩坑,比如下面所示的代码,预期的输出结果是3550,但实际上并不是:

BigDecimal bigDecimal = new BigDecimal("3550.00");
System.out.println(bigDecimal.stripTrailingZeros().toString());
//输出结果:3.55E+3

//使用toPlainString()方法可以避免这个问题,如下所示:
System.out.println( new BigDecimal("0.000000000000").toPlainString());
System.out.println( new BigDecimal("1E+11").toPlainString());
System.out.println(new BigDecimal("3550.00").stripTrailingZeros().toPlainString());

//输出结果:
//0.000000000000
//100000000000
//3550
复制代码

其实,BigDecimal提供了3个转换为String的方法,分别为:

  1. toString() 某些场景下使用科学计数法

  2. toPlainString() 不使用任何计数法

  3. toEngineeringString() 某些场景下使用工程计数法

这里简单提下科学计数法和工程计数法的区别:

科学记数法,是将数字表示成10的幂的倍数的形式。

工程记数法,是在科学记数法基础上,将10的幂限制为3的倍数。

举例:

原始值 科学技术法 工程计数法
2700 2.7 x 10³ 2.7 x 10³
27000 2.7 x 10⁴ 27 x 10³
270000 2.7 x 10⁵ 270 x 10³
2700000 2.7 x 10⁶ 2.7 x 10⁶

示例代码:

BigDecimal bigDecimal = new BigDecimal("270000.00").stripTrailingZeros();
System.out.println(bigDecimal.toString());
System.out.println(bigDecimal.toPlainString());
System.out.println(bigDecimal.toEngineeringString());

//输出结果:
//2.7E+5
//270000
//270E+3
复制代码

使用规范

尽量不要在项目中使用new BigDecimal("0"),而是使用BigDecimal提供的常量BigDecimal.ZERO

BigDecimal zero = BigDecimal.ZERO;
BigDecimal one = BigDecimal.ONE;
BigDecimal ten = BigDecimal.TEN;
复制代码

Supongo que te gusta

Origin juejin.im/post/7079982213856493604
Recomendado
Clasificación