【问题标题】:Rounding Currency to Nearest Dollar, how did you do it?将货币四舍五入到最接近的美元,你是怎么做到的?
【发布时间】:2012-10-19 02:57:04
【问题描述】:

以下代码适用于我的生产应用程序中的所有手机,但运行 4.1.2 的 Galaxy Nexus 除外。 Play商店给我发了错误,我先贴代码,再贴错误:

    // Roughly formats the currency by loping off the decimal places (amount
// comes already rounded)
public static String formatCurrencyRound(double amount) {
    String currency = formatCurrency(amount); // Returns "$8.00"

    return currency.substring(0, currency.indexOf("."));
}

错误:

java.lang.RuntimeException: Unable to resume activity {com.ootpapps.saving.made.simple/com.ootpapps.saving.made.simple.SavingsPlanOverview}: java.lang.StringIndexOutOfBoundsException: length=9; regionStart=0; regionLength=-1
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.StringIndexOutOfBoundsException: length=9; regionStart=0; regionLength=-1
at java.lang.String.startEndAndLength(String.java:593)
at java.lang.String.substring(String.java:1474)
at com.ootpapps.saving.made.simple.App.formatCurrencyRound(App.java:68)
at com.ootpapps.saving.made.simple.SavingsPlanOverview.updateSavingsPlanWidgets(SavingsPlanOverview.java:224)
at com.ootpapps.saving.made.simple.SavingsPlanOverview.onResume(SavingsPlanOverview.java:156)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1184)
at android.app.Activity.performResume(Activity.java:5082)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565)
... 12 more

如果有人可以提出一种更好的方法来将此货币字符串舍入,或者将原始数字舍入为没有小数的格式化字符串,我将不胜感激。同样,由于某种原因,这仅在运行 4.1.2 的 GNexus 上失败。

谢谢!

编辑添加格式货币代码:

public static String formatCurrency(double amount) {
    NumberFormat currency = NumberFormat.getCurrencyInstance();

    return currency.format(amount);
}

继续编辑 - 我使用的代码可以将货币四舍五入到整美元:

public static String formatCurrencyWhole(double amount) {
    NumberFormat currency = NumberFormat.getCurrencyInstance();
    currency.setMaximumFractionDigits(0);
    currency.setMinimumFractionDigits(0);

    return currency.format(amount);
}

【问题讨论】:

  • 如果你还想向下取整,你考虑过 Math.floor() 吗?
  • 你能贴出formatCurrency(Double)的代码吗?
  • 最终:我会使用 NumberFormat,只需将 FractionDigits 设置为 0 的 Max 和 Min。我当时不知道这种方法存在,对我来说似乎有点不正统,也许措辞“分数”而不是“小数”让我失望。无论如何,上面的设置器强制数字的小数为 0,因此,数字将始终是整数。
  • 是的,但这些答案都不是,这是我在上面发布的。

标签: android exception currency rounding


【解决方案1】:

首先,永远永远、不应该使用doubles 处理货币。您应该使用BigDecimal 来保持精度。 (有关更多信息,请参阅this question。)

除此之外,您可以使用NumberFormat 来获取您的String 表示:

NumberFormat format = NumberFormat.getCurrencyInstance(Locale.US);
String result = format.format(amount);

.format() 取双倍;如果您最终使用BigDecimal,请使用bigDecimal.doubleValue()。 This answer 提供了这方面的一些额外细节。

【讨论】:

  • +1 为实际答案,但如果发帖人截断小数点分隔符后的所有内容,那么精度显然并不重要。 :-)
  • 也许不是为了展示,但绝对是为了存储!请记住,如果精度差最终导致他的价格从 8.499 美元降到 8.500 美元,它将显示为 9 美元而不是 8 美元。
  • 嗯...不,不会的。如果你有$8.499 并截断小数点,你就有$8。如果您有$8.500 并在小数点处截断,则您有$8。正如我所说,如果你在小数点处截断,那么精度显然并不重要。
  • 那么 7.999 美元对 8.000 美元的情况可能更好。 (对不起,我误读了你的第一条评论。)
  • :-) 很高兴看到我们这些老人仍然可以像你们这些年轻人一样阅读。 ;-)
【解决方案2】:

我认为字符串的格式已经是 $8

如果小数不存在:

currency.substring(0, currency.indexOf("."));

将抛出 IndexOutOfBoundsException。

解决方案可能就像事先测试小数一样简单。

public static String formatCurrencyRound(double amount) { 字符串货币 = formatCurrency(amount); // 返回“$8.00”

if(currency.indexOf(".") != -1){
   return currency.substring(0, currency.indexOf("."));
}else{
   return currency;
}

}

------- 编辑 ----------

正如 Ken(非常聪明的人)在 cmets 中指出的那样,堆栈跟踪中的关键行是:

java.lang.StringIndexOutOfBoundsException: 长度=9;区域开始=0;区域长度=-1 在 java.lang.String.startEndAndLength(String.java:593)

此错误显示 regionLength = -1,这意味着 indexOf(".") 的结果为 -1。 ((".") 不存在)

它还显示字符串长度为 9,这让我认为不同的分隔符问题(Ken 也指出)可能是真正的问题。除非美元金额在 $10000000 范围内。

这就是为什么我想查看 formatCurrency(Double); 的代码的原因

-----编辑-----

怀疑您使用的是默认语言环境:

NumberFormat 货币 = NumberFormat.getCurrencyInstance();

文档对此有这样的说法:

http://developer.android.com/reference/java/util/Locale.html

“默认的语言环境不适合机器可读的输出。最好的选择通常是 Locale.US - 这个语言环境保证在所有设备上都可用,事实上它没有令人惊讶的特殊情况并且经常使用(尤其是用于计算机-计算机通信)意味着它也往往是最有效的选择。

一个常见的错误是在生成机器可读的输出时隐式使用默认语言环境。这往往适用于开发人员的测试设备(特别是因为有很多开发人员使用 en_US),但在用户处于更复杂语言环境的设备上运行时会失败。”

除非您的应用需要外币,否则请使用:

NumberFormat 货币 = NumberFormat.getCurrencyInstance(Locale.US);

【讨论】:

  • +1。我打败了你(20 秒),但你的答案包括替换代码块,而我(现已删除)的答案没有,让你的答案更好。
  • @ken 你在我 +1 之前删除了你的...你指出不同的分隔符会导致同样的问题。我现在正在研究什么情况可能会导致使用不同的分隔符。也许是外币?
  • 是的。美国以外的许多国家/地区使用不同的小数分隔符(例如,),这会导致问题。我将帮助您进行研究 - 请参阅 decimal_marks 了解有关哪些(以及在哪里)的一些信息。 :-) 此外,堆栈跟踪中的关键行是第 15 行(带有StringIndexOutOfBounds),您可能希望将其添加到您的答案中。
  • 不应该对发帖人的评论而不是你自己的答案吗? ;-)
  • 需要外币。这就是我没有使用 Locale.US 的原因。
猜你喜欢
  • 2012-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多