我们可以使用double来存储货币字段并使用BigDecimal进行算术运算

los*_*ney 5 java double bigdecimal

我知道double/float的问题,建议使用BigDecimal而不是double/float来表示货币字段.但是双/浮动更有效且节省空间.然后我的问题是:使用double/float来表示Java类中的货币字段是可以接受的,但是使用BigDecimal来处理算术(即在任何算术之前将double/float转换为BigDecimal)和等同检查?

原因是节省了一些空间.我真的看到很多项目正在使用double/float来代表货币领域.

这有什么陷阱吗?提前致谢.

Tom*_*icz 8

不,你不能.

假设double足以存储两个值xy.然后你将它们转换为安全BigDecimal和多个.结果是准确的,但是如果将乘法结果存回double,很可能会失去精度.证明:

double x = 1234567891234.0;
double y = 1234567891234.0;
System.out.println(x);
System.out.println(y);

BigDecimal bigZ = new BigDecimal(x).multiply(new BigDecimal(y));
double z = bigZ.doubleValue();
System.out.println(bigZ);
System.out.println(z);
Run Code Online (Sandbox Code Playgroud)

结果:

1.234567891234E12          //precise 'x'
1.234567891234E12          //precise 'y'
 1524157878065965654042756  //precise 'x * y'
1.5241578780659657E24      //loosing precision
Run Code Online (Sandbox Code Playgroud)

x并且y准确,以及使用乘法BigDecimal.然而,在回到double我们松散的最低有效数字后.


Dun*_*ear 6

我还建议您只使用BigDecimal进行可能涉及货币的所有算术.

确保始终使用BigDecimal的String构造函数.为什么?在JUnit测试中尝试以下代码:

assertEquals(new BigDecimal("0.01").toString(), new BigDecimal(0.01).toString());
Run Code Online (Sandbox Code Playgroud)

您将获得以下输出:

expected:<0.01[]> but was <0.01[000000000000000020816681711721685132943093776702880859375]>
Run Code Online (Sandbox Code Playgroud)

事实是,你不能完全存储0.01作为'双倍'数量.只有BigDecimal的存储您所需要的数量EXACTLY只要你想它.

请记住,BigDecimal是不可变的.以下将编译:

BigDecimal amount = new BigDecimal("123.45");
BigDecimal more = new BigDecimal("12.34");
amount.add(more);
System.out.println("Amount is now: " + amount);
Run Code Online (Sandbox Code Playgroud)

但结果输出将是:

金额现在是:123.45

那是因为你需要将结果分配给一个新的(或相同的)BigDecimal变量.

换一种说法:

amount = amount.add(more)
Run Code Online (Sandbox Code Playgroud)