解析货币串安全的最佳方法?

gst*_*low -1 java string currency

在服务器上我接受String作为参数.这个字符串代表钱.

它可能是(例如)

0  
12  
12,  
12,34  
,12
Run Code Online (Sandbox Code Playgroud)

现在我这样削减它:

long centAmount = (long) (NumberFormat.getInstance(Locale.FRANCE).parse(outSum).doubleValue() * 100)
Run Code Online (Sandbox Code Playgroud)

我担心我会在某处丢失一分钱.

请告知如何重写我的代码.

Pet*_*rey 5

当你使用(long)它时截断数字.这意味着0.999999999999999将被截断到0哪里将失去你在这里和那里的一分钱.更好的方法是使用舍入.

double input = NumberFormat.getInstance(Locale.FRANCE).parse(outSum).doubleValue();
long centAmount = Math.round(input * 100);
Run Code Online (Sandbox Code Playgroud)

这将适用于价值高达70万亿美元的价值.如果您需要准确存储更大的数量,则需要使用BigDecimal和BigInteger.

使用BigDecimal的一个优点是它会提醒你什么时候应该使用舍入(并不总是,但如果你不确定它不容易出错)缺点是代码更加麻烦.

如果你使用BigDecimal,你可以这样做

DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.FRANCE);
df.setParseBigDecimal(true);
BigDecimal bd = (BigDecimal) df.parseObject(outSum);
BigDecimal bd100 = bd.multiply(BigDecimal.valueOf(100))
                     .setScale(0, RoundingMode.HALF_UP);
long centAmount = bd100.longValue();
Run Code Online (Sandbox Code Playgroud)

添加一个简单的例子,说明为什么BigDecimal不能解决所有问题,但它确实隐藏了它们.

    BigDecimal add = new BigDecimal("1.00")
              .divide(BigDecimal.valueOf(3), 2, BigDecimal.ROUND_HALF_UP)
              .multiply(BigDecimal.valueOf(3)).add(new BigDecimal("0.01"));
    System.out.println(add);
    double add2 = 1.0 / 3 * 3 +  0.01;
    System.out.println(add2);
Run Code Online (Sandbox Code Playgroud)

这打印

1.00
1.01
Run Code Online (Sandbox Code Playgroud)

哪一个更容易出错,你可以争论任何一种方式(这可能是基于你的团队,他们发现哪些更容易出错),但哪一个更难理解它想要做什么?

我对BigDecimal的问题是黑白评估double是有缺陷的,BigDecimal会解决你所有的问题,实际上,你得到了所有相同的问题但是使用BigDecimal它们可能更难发现,所以你可能永远不会知道你有问题.

有了双倍,如果你看到1.0999999999999998你认为,那看起来不对,但有了BigDecimal,你可能会看到1.00并认为看起来不错.