4

我对如何MonetaryAmountFormat使用 Moneta JSR-354 实现自定义 a 感到非常困惑。

我的意图是能够同时解析和1.23解析。$3.45MonetaryAmount

这是我的单元测试:

@Test
public void testString() {
    Bid bid = new Bid("1.23");
    assertEquals(1.23, bid.getValue(), 0.0);
    System.out.println(bid);

    bid = new Bid("$3.45");
    assertEquals(3.45, bid.getValue(), 0.0);
    System.out.println(bid);
}

这是我的课:

public final class Bid {

    private static final CurrencyUnit USD = Monetary.getCurrency("USD");
    private MonetaryAmount bid;

    /**
     * Constructor.
     *
     * @param bidStr the bid
     */
    public Bid(String bidStr) {
        MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(
                AmountFormatQueryBuilder.of(Locale.US)
                .set("pattern", "###.##")
                .build());
        if (StringUtils.isNotBlank(bidStr)) {
            bidStr = bidStr.trim();
            bidStr = bidStr.startsWith("$") ? bidStr.substring(1) : bidStr;
            try {
                bid = FastMoney.parse(bidStr, format);
            } catch (NumberFormatException e) {
                bid = FastMoney.of(0, USD);
            }
        }
    }

    /**
     * Constructor.
     *
     * @param bidDouble the bid
     */
    public Bid(double bidDouble) {
        bid = FastMoney.of(bidDouble, USD);
    }

    public double getValue() {
        return bid.getNumber().doubleValue();
    }
}

我真的很希望能够解析bidStr有或没有$使用 single MonetaryAmountFormat,但是在花了很多时间试图找出如何使$optional 之后,我放弃了。不幸的是,我什至无法弄清楚如何将其1.23解析为美元。莫内塔投出一个NullPointerException。我应该使用 设置货币AmountFormatQueryBuilder吗?可以使用 设置的所有键是AmountFormatQueryBuilder什么?我搜索了文档,但除了几个常用键(例如pattern.

4

2 回答 2

7

1.23在尝试解析不合格的数字(如)时,JavaMoney 似乎无法正常工作。

默认情况下,MonetaryAmountFormat希望您提供货币名称(如USD 1.23):

MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.US);
MonetaryAmount amount = format.parse("USD 1.23");

如果您设置CurrencyStyle.SYMBOL,那么您可以按货币名称或符号解析(因此,要么 要么USD 1.23$3.45

AmountFormatQuery formatQuery = AmountFormatQueryBuilder.of(Locale.US)
    .set(CurrencyStyle.SYMBOL)
    .build();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(formatQuery);
MonetaryAmount amount1 = format.parse("USD 1.23");
MonetaryAmount amount2 = format.parse("$3.45");

这可能是您使用 JavaMoney 获得的最接近的结果。

如果你知道你只是从同一种货币中获取数字,你最好在别处解析字符串(使用正则表达式或其他东西)并转换为一致的输入格式,因为(正如你所发现的),你很容易得到NullPointerExceptions 而没有任何解释JavaMoney 很不高兴。

至于可用的键,您可以查看org.javamoney.moneta.format.AmountFormatParams: pattern, groupingSizes,上的常量groupingSeparators

设置格式时,请务必注意必须使用通用货币符号: ¤。例如,您可能会这样做.set("pattern", "¤#,##0.00")

FastMoney最后,您可以直接从 a 解析,而不是直接使用 Moneta RI 中的类MonetaryAmountFormat

// rather than using Monata directly:
MonetaryAmount amount = FastMoney.parse(bidStr, format);

// use the API:
MonetaryAmount amount = format.parse(bidStr);
于 2016-04-29T22:41:01.567 回答
1

如果您使用的是自定义格式模式,那么您可以解析仅包含数字而没有货币的字符串,但您应该自己指定预期的货币。这是一个例子:

@Test
public void testParse_pattern_without_currency_sign_but_with_currency_in_context() {
    CurrencyUnit usd = Monetary.getCurrency("USD");
    AmountFormatContextBuilder builder = AmountFormatContextBuilder.of(US);
    builder.set(AmountFormatParams.PATTERN, "0.00"); // the pattern doesn't contains a currency sign ¤
    builder.set(CurrencyUnit.class, usd); // set expected currency
    AmountFormatContext context = builder.build();
    DefaultMonetaryAmountFormat format = new DefaultMonetaryAmountFormat(context);
    MonetaryAmount parsedAmount = format.parse("0.01 USD");
    assertSame(parsedAmount.getCurrency(), usd);
    assertEquals(parsedAmount.getNumber().doubleValueExact(), 0.01D);
    assertEquals(parsedAmount.toString(), "USD 0.01");
}

请注意,您需要使用set(CurrencyUnit.class, usd).

但是,如果您尝试使用货币符号设置模式,例如0.00 ¤,您将收到错误消息:javax.money.format.MonetaryParseException: Error parsing CurrencyUnit: no input.

我创建了一张票Lenient Formatter: Parse a string with a number 但没有货币代码,请阅读并添加您的意见。

于 2019-02-17T20:15:50.000 回答