Converting Integer to BigDecimal in Java – 在 Java 中将整数转换为大十进制

最后修改: 2024年 1月 14日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

BigDecimal is designed to work with large floating point numbers. It solves the problem with floating point arithmetic and provides a way to control the precision. Additionally, it has plenty of conventional methods for operations over the numbers.

BigDecimal 设计用于处理大浮点数。它解决了浮点运算的问题,并提供了一种控制精度的方法。此外,它还提供了大量对数字进行运算的常规方法。

We can leverage the features of BigDecimal by converting an Integer. In this tutorial, we’ll learn several ways to do this and discuss their pros and cons.

我们可以通过转换 Integer 来利用 BigDecimal 的功能。在本教程中,我们将学习几种方法,并讨论它们的优缺点。

2. Constructor Conversion

2.构造器转换

One of the most straightforward ways to use constructor conversion. BigDecimal exposes constructors that can convert from a wide range of inputs. Thus, we can pass a given Integer to the BigDecimal constructor:

使用构造函数转换的最直接方法之一。BigDecimal提供的构造函数可以从多种输入进行转换。因此,我们可以将给定的 Integer 传递给 BigDecimal 构造函数:

@ParameterizedTest
@ArgumentsSource(BigDecimalConversionArgumentsProvider.class)
void giveIntegerWhenConvertWithConstructorToBigDecimalThenConversionCorrect(Integer given, BigDecimal expected) {
    BigDecimal actual = new BigDecimal(given);
    assertThat(actual).isEqualTo(expected);
}

However, with this approach, we’ll force BigDecimal to create a new object every time:

然而,通过这种方法,我们将迫使 BigDecimal 每次都创建一个新对象: <br

@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
void giveIntegerWhenConvertWithConstructorToBigDecimalThenConversionWithoutCaching(Integer given) {
    BigDecimal firstBigDecimal = new BigDecimal(given);
    BigDecimal secondBigDecimal = new BigDecimal(given);
    assertThat(firstBigDecimal)
      .isEqualTo(secondBigDecimal)
      .isNotSameAs(secondBigDecimal);
}

3. Static Factory Conversion

3.静态工厂转换

Another technique involves a static factory, and it’s similar to the previous example:

另一种技术涉及 static 工厂,它与前面的示例类似:

@ParameterizedTest
@ArgumentsSource(BigDecimalConversionArgumentsProvider.class)
void giveIntegerWhenConvertWithValueOfToBigDecimalThenConversionCorrect(Integer given, BigDecimal expected) {
    BigDecimal actual = BigDecimal.valueOf(given);
    assertThat(actual).isEqualTo(expected);
}

It provides one benefit: it can cache values, unlike constructor conversion. Thus, we can reuse the same object in different contexts. Because BigDecimal is immutable, it doesn’t create any problems.

它有一个好处:与构造函数转换不同,它可以缓存值。因此,我们可以在不同的上下文中重复使用同一个对象。由于 BigDecimalimmutable 对象,因此不会产生任何问题。

4. Caching

4.缓存

The BigIntegers.valueOf() factory caches the values from zero to ten. All the values are defined in the static ZERO_THROUGH_TEN array inside the BigDecimal class:

BigIntegers.valueOf()工厂缓存从零到十的值。所有值都定义在 BigDecimal 类中的静态 ZERO_THROUGH_TEN 数组中:

private static final BigDecimal[] ZERO_THROUGH_TEN = {
  new BigDecimal(BigInteger.ZERO,       0,  0, 1),
  new BigDecimal(BigInteger.ONE,        1,  0, 1),
  new BigDecimal(BigInteger.TWO,        2,  0, 1),
  new BigDecimal(BigInteger.valueOf(3), 3,  0, 1),
  new BigDecimal(BigInteger.valueOf(4), 4,  0, 1),
  new BigDecimal(BigInteger.valueOf(5), 5,  0, 1),
  new BigDecimal(BigInteger.valueOf(6), 6,  0, 1),
  new BigDecimal(BigInteger.valueOf(7), 7,  0, 1),
  new BigDecimal(BigInteger.valueOf(8), 8,  0, 1),
  new BigDecimal(BigInteger.valueOf(9), 9,  0, 1),
  new BigDecimal(BigInteger.TEN,        10, 0, 2),
};

The valueOf(long) factory uses this array inside:

valueOf(long)工厂内部使用此数组:

public static BigDecimal valueOf(long val) {
    if (val >= 0 && val < ZERO_THROUGH_TEN.length)
        return ZERO_THROUGH_TEN[(int)val];
    else if (val != INFLATED)
        return new BigDecimal(null, val, 0, 0);
    return new BigDecimal(INFLATED_BIGINT, val, 0, 0);
}

We can see that for certain values, the BigDecimal objects are the same:

我们可以看到,对于某些值, BigDecimal 对象是相同的:

@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
void giveIntegerWhenConvertWithValueOfToBigDecimalThenConversionCachesTheResults(Integer given) {
    BigDecimal firstBigDecimal = BigDecimal.valueOf(given);
    BigDecimal secondBigDecimal = BigDecimal.valueOf(given);
    assertThat(firstBigDecimal).isSameAs(secondBigDecimal);
}

This might benefit performance if we use many BigDecimal values from zero to ten. Also, as BigDecimal objects are immutable, we can implement our cache for the numbers we use repeatedly in our application.

如果我们使用很多从 0 到 10 的 BigDecimal 值,这可能会有利于提高性能。此外,由于 BigDecimal 对象是不可变的,我们可以为应用程序中重复使用的数字实现 我们的缓存

At the same time, the numbers outside of this range won’t use caching:

同时,在此范围之外的数字不会使用缓存:

@ParameterizedTest
@ValueSource(ints = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21})
void giveIntegerWhenConvertWithValueOfToBigDecimalThenConversionWontCacheTheResults(Integer given) {
    BigDecimal firstBigDecimal = BigDecimal.valueOf(given);
    BigDecimal secondBigDecimal = BigDecimal.valueOf(given);
    assertThat(firstBigDecimal)
      .isEqualTo(secondBigDecimal)
      .isNotSameAs(secondBigDecimal);
}

Thus, relying on identity equality in the production code isn’t advisable.

因此,在生产代码中依赖身份平等并不可取。

5. Conclusion

5.结论

BigDecimal is a good choice when we need to make operations on floating point numbers, avoiding rounding errors. Also, it allows us to use massive numbers that cannot be represented otherwise. BigDecimal provides various methods for conversion from other types, for example, from an Integer.

当我们需要对浮点数进行运算时,BigDecimal 是一个不错的选择,可以避免四舍五入的错误。此外,它还允许我们使用无法以其他方式表示的大量数字。BigDecimal 提供了多种从其他类型转换的方法,例如,从 Integer 转换。

As usual, all the code from this tutorial is available over on GitHub.

与往常一样,本教程中的所有代码都可以在 GitHub 上获取