>  기사  >  Java  >  Java 9의 새로운 통화 API

Java 9의 새로운 통화 API

伊谢尔伦
伊谢尔伦원래의
2016-11-26 10:10:551445검색

JSR 354는 Java 9에서 공식적으로 도입될 예정인 새로운 Java 통화 API를 정의합니다. 이 기사에서는 참조 구현인 JavaMoney의 현재 진행 상황을 살펴보겠습니다.

Java 8의 새로운 날짜 및 시간 API에 대한 이전 기사와 마찬가지로 이 기사에서는 주로 일부 코드를 통해 새로운 API의 사용법을 보여줍니다.

시작하기 전에 사양에 정의된 이 새로운 API 세트의 목적을 한 단락으로 간략하게 요약하고 싶습니다.

많은 애플리케이션에서 금전적 가치가 핵심입니다. 그러나 JDK는 이를 거의 지원하지 않습니다. 엄밀히 말하면 기존 java.util.Currency 클래스는 현재 ISO 4217 통화의 데이터 구조만 나타낼 뿐 관련 값이나 사용자 정의 통화는 없습니다. JDK에는 통화 값을 나타낼 수 있는 표준 유형은 물론 통화 연산 및 변환에 대한 기본 지원도 없습니다.

Maven을 사용하는 경우 참조 구현의 현재 기능을 경험하려면 프로젝트에 다음 참조만 추가하면 됩니다.

<dependency>
  <groupId>org.javamoney</groupId>
  <artifactId>moneta</artifactId>
  <version>0.9</version>
</dependency>

사양에 언급된 클래스와 인터페이스는 다음과 같습니다. javax.money.* 패키지 아래에 있습니다.

두 가지 핵심 인터페이스인 MoneyUnit과 MonetaryAmount부터 시작해 보겠습니다.

CurrencyUnit 및 MonetaryAmount

CurrencyUnit은 통화를 나타냅니다. 이는 사용자 정의 구현을 지원한다는 점을 제외하면 현재 java.util.Currency 클래스와 다소 유사합니다. 표준 정의에서 java.util.Currency도 이 인터페이스를 구현할 수 있습니다. MoneyUnit의 인스턴스는 MonetaryCurrities 팩토리를 통해 얻을 수 있습니다.

// 根据货币代码来获取货币单位 CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");
    CurrencyUnit usDollar = MonetaryCurrencies.getCurrency("USD"); // 根据国家及地区来获取货币单位
    CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN); CurrencyUnit
    canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);

MontetaryAmount는 특정 통화의 특정 금액을 나타냅니다. 일반적으로 이는 MoneyUnit에 바인딩됩니다.

CurrencyUnit과 마찬가지로 MontetaryAmount도 여러 구현을 지원할 수 있는 인터페이스입니다.

CurrencyUnit 및 MontetaryAmount의 구현은 변경이 불가능하고 스레드로부터 안전하며 비교 가능해야 합니다.

/ get MonetaryAmount from CurrencyUnit
CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");
MonetaryAmount fiveEuro = Money.of(5, euro);
  
// get MonetaryAmount from currency code
MonetaryAmount tenUsDollar = Money.of(10, "USD");
  
// FastMoney is an alternative MonetaryAmount factory that focuses on performance
MonetaryAmount sevenEuro = FastMoney.of(7, euro);

Money와 FastMoney는 JavaMoney 라이브러리에서 MonetaryAmount를 구현한 두 가지입니다. Money는 BigDecimal을 사용하여 금액을 저장하는 기본 구현입니다. FastMoney는 긴 유형을 사용하여 금액을 저장하는 선택적 구현입니다. 문서에 따르면 FastMoney의 작업은 Money의 작업보다 약 10~15배 빠릅니다. 그러나 FastMoney의 금액 크기와 정밀도는 Long 유형으로 제한됩니다.

여기서 Money 및 FastMoney는 특정 구현 클래스입니다(javax.money.*가 아닌 org.javamoney.moneta.* 패키지에 있음). 특정 유형을 지정하지 않으려는 경우 MonetaryAmountFactory를 사용하여 MonetaryAmount 인스턴스를 생성할 수 있습니다.

MonetaryAmount specAmount = MonetaryAmounts.getDefaultAmountFactory()
                .setNumber(123.45) .setCurrency("USD") .create();

이러한 두 MontetaryAmount 인스턴스는 구현 클래스인 통화가 동일한 경우에만 동일한 것으로 간주됩니다. 단위와 가치는 모두 동일합니다.

MonetaryAmount oneEuro = Money.of(1, MonetaryCurrencies.getCurrency("EUR"));
boolean isEqual = oneEuro.equals(Money.of(1, "EUR")); // true
boolean isEqualFast = oneEuro.equals(FastMoney.of(1, "EUR")); // false

MonetaryAmount에는 특정 통화, 금액, 정밀도 등을 얻는 데 사용할 수 있는 다양한 방법이 포함되어 있습니다.

MonetaryAmount monetaryAmount = Money.of(123.45, euro);
CurrencyUnit currency = monetaryAmount.getCurrency();
NumberValue numberValue = monetaryAmount.getNumber();
  
int intValue = numberValue.intValue(); // 123
double doubleValue = numberValue.doubleValue(); // 123.45
long fractionDenominator = numberValue.getAmountFractionDenominator(); // 100
long fractionNumerator = numberValue.getAmountFractionNumerator(); // 45
int precision = numberValue.getPrecision(); // 5
  
// NumberValue extends java.lang.Number.
// So we assign numberValue to a variable of type Number
Number number = numberValue;

MonetaryAmount 사용

는 MonetaryAmount의 산술 연산에서 찾을 수 있습니다:

MonetaryAmount twelveEuro = fiveEuro.add(sevenEuro); // "EUR 12"
MonetaryAmount twoEuro = sevenEuro.subtract(fiveEuro); // "EUR 2"
MonetaryAmount sevenPointFiveEuro = fiveEuro.multiply(1.5); // "EUR 7.5"
  
// MonetaryAmount can have a negative NumberValue
MonetaryAmount minusTwoEuro = fiveEuro.subtract(sevenEuro); // "EUR -2"
  
// some useful utility methods
boolean greaterThan = sevenEuro.isGreaterThan(fiveEuro); // true
boolean positive = sevenEuro.isPositive(); // true
boolean zero = sevenEuro.isZero(); // false
  
// Note that MonetaryAmounts need to have the same CurrencyUnit to do mathematical operations
// this fails with: javax.money.MonetaryException: Currency mismatch: EUR/USD
fiveEuro.add(tenUsDollar);

반올림 연산은 금액 변환에서 매우 중요한 부분입니다. MonetaryAmount는 반올림 연산자를 사용하여 반올림할 수 있습니다.

CurrencyUnit usd = MonetaryCurrencies.getCurrency("USD");
MonetaryAmount dollars = Money.of(12.34567, usd);
MonetaryOperator roundingOperator = MonetaryRoundings.getRounding(usd);
MonetaryAmount roundedDollars = dollars.with(roundingOperator); // USD 12.35

여기서 12.3456 미국 달러는 현재 통화의 기본 반올림 규칙에 따라 변환됩니다.

MonetaryAmount 컬렉션을 운영할 때 필터링, 정렬, 그룹화에 사용할 수 있는 실용적인 도구와 방법이 많이 있습니다. 이러한 메서드는 Java 8의 스트림 API와 함께 사용할 수도 있습니다.

다음 컬렉션을 살펴보세요.

List<MonetaryAmount> amounts = new ArrayList<>();
amounts.add(Money.of(2, "EUR"));
amounts.add(Money.of(42, "USD"));
amounts.add(Money.of(7, "USD"));
amounts.add(Money.of(13.37, "JPY"));
amounts.add(Money.of(18, "USD"));

CurrencyUnit을 기준으로 금액을 필터링할 수 있습니다.

CurrencyUnit yen = MonetaryCurrencies.getCurrency("JPY");
CurrencyUnit dollar = MonetaryCurrencies.getCurrency("USD");
// 根据货币过滤,只返回美金
// result is [USD 18, USD 7, USD 42]
List<MonetaryAmount> onlyDollar = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar))
    .collect(Collectors.toList());
  
// 根据货币过滤,只返回美金和日元
// [USD 18, USD 7, JPY 13.37, USD 42]
List<MonetaryAmount> onlyDollarAndYen = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar, yen))
    .collect(Collectors.toList());

더 큰 금액을 필터링할 수도 있습니다. 특정 임계값 이하 금액:

MonetaryAmount tenDollar = Money.of(10, dollar);
  
// [USD 42, USD 18]
List<MonetaryAmount> greaterThanTenDollar = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar))
    .filter(MonetaryFunctions.isGreaterThan(tenDollar))
    .collect(Collectors.toList());

정렬도 유사합니다:

// Sorting dollar values by number value
// [USD 7, USD 18, USD 42]
List<MonetaryAmount> sortedByAmount = onlyDollar.stream()
    .sorted(MonetaryFunctions.sortNumber())
    .collect(Collectors.toList());
  
// Sorting by CurrencyUnit
// [EUR 2, JPY 13.37, USD 42, USD 7, USD 18]
List<MonetaryAmount> sortedByCurrencyUnit = amounts.stream()
    .sorted(MonetaryFunctions.sortCurrencyUnit())
    .collect(Collectors.toList());

그룹화 작업도 있습니다:

// 按货币单位进行分组
// {USD=[USD 42, USD 7, USD 18], EUR=[EUR 2], JPY=[JPY 13.37]}
Map<CurrencyUnit, List<MonetaryAmount>> groupedByCurrency = amounts.stream()
    .collect(MonetaryFunctions.groupByCurrencyUnit());
  
// 分组并进行汇总
Map<CurrencyUnit, MonetarySummaryStatistics> summary = amounts.stream()
    .collect(MonetaryFunctions.groupBySummarizingMonetary()).get();
  
// get summary for CurrencyUnit USD
MonetarySummaryStatistics dollarSummary = summary.get(dollar);
MonetaryAmount average = dollarSummary.getAverage(); // "USD 22.333333333333333333.."
MonetaryAmount min = dollarSummary.getMin(); // "USD 7"
MonetaryAmount max = dollarSummary.getMax(); // "USD 42"
MonetaryAmount sum = dollarSummary.getSum(); // "USD 67"
long count = dollarSummary.getCount(); // 3

MonetaryFunctions 최대값, 최소값 및 합계를 구하는 데 사용할 수 있는 축소 기능도 제공합니다.

List<MonetaryAmount> amounts = new ArrayList<>();
amounts.add(Money.of(10, "EUR"));
amounts.add(Money.of(7.5, "EUR"));
amounts.add(Money.of(12, "EUR"));
  
Optional<MonetaryAmount> max = amounts.stream().reduce(MonetaryFunctions.max()); // "EUR 7.5"
Optional<MonetaryAmount> min = amounts.stream().reduce(MonetaryFunctions.min()); // "EUR 12"
Optional<MonetaryAmount> sum = amounts.stream().reduce(MonetaryFunctions.sum()); //

사용자 정의된 MonetaryAmount 작업

MonetaryAmount는 MonetaryOperator라는 매우 친숙한 확장 지점도 제공합니다. . MonetaryOperator는 MonetaryAmount 입력 매개변수를 수신하고 새 MonetaryAmount 개체를 반환하는 기능적 인터페이스입니다.

// A monetary operator that returns 10% of the input MonetaryAmount
// Implemented using Java 8 Lambdas
MonetaryOperator tenPercentOperator = (MonetaryAmount amount) -> {
  BigDecimal baseAmount = amount.getNumber().numberValue(BigDecimal.class);
  BigDecimal tenPercent = baseAmount.multiply(new BigDecimal("0.1"));
  return Money.of(tenPercent, amount.getCurrency());
};
  
MonetaryAmount dollars = Money.of(12.34567, "USD");
  
// apply tenPercentOperator to MonetaryAmount
MonetaryAmount tenPercentDollars = dollars.with(tenPercentOperator); // USD 1.234567

표준 API 기능은 MonetaryOperator 인터페이스를 통해 구현됩니다. 예를 들어 앞서 본 반올림 연산은 MonetaryOperator 인터페이스 형태로 제공됩니다.

환율

환율은 ExchangeRateProvider를 통해 확인할 수 있습니다. JavaMoney에는 다양한 ExchangeRateProvider 구현이 함께 제공됩니다. 가장 중요한 두 가지는 ECBCurrentRateProvider와 IMFRateProvider입니다.

ECBCurrentRateProvider는 유럽중앙은행(ECB)의 데이터를 쿼리하고 IFRateProvider는 국제통화기금(IMF)의 환율을 쿼리합니다.

// get the default ExchangeRateProvider (CompoundRateProvider)
ExchangeRateProvider exchangeRateProvider = MonetaryConversions.getExchangeRateProvider();
  
// get the names of the default provider chain
// [IDENT, ECB, IMF, ECB-HIST]
List<String> defaultProviderChain = MonetaryConversions.getDefaultProviderChain();
  
// get a specific ExchangeRateProvider (here ECB)
ExchangeRateProvider ecbExchangeRateProvider = MonetaryConversions.getExchangeRateProvider("ECB");

ExchangeRateProvider를 지정하지 않으면CompoundRateProvider가 반환됩니다. CompoundRateProvider는 환율 변환 요청을 ExchangeRateProvider 체인에 위임하고 정확한 결과를 반환하는 첫 번째 공급자로부터 데이터를 반환합니다.

// get the exchange rate from euro to us dollar
ExchangeRate rate = exchangeRateProvider.getExchangeRate("EUR", "USD");
  
NumberValue factor = rate.getFactor(); // 1.2537 (at time writing)
CurrencyUnit baseCurrency = rate.getBaseCurrency(); // EUR
CurrencyUnit targetCurrency = rate.getCurrency(); // USD

통화 변환

ExchangeRateProvider에서 반환한 CurrentConversions를 통해 서로 다른 통화 간의 변환을 완료할 수 있습니다.

// get the CurrencyConversion from the default provider chain
CurrencyConversion dollarConversion = MonetaryConversions.getConversion("USD");
  
// get the CurrencyConversion from a specific provider
CurrencyConversion ecbDollarConversion = ecbExchangeRateProvider.getCurrencyConversion("USD");
  
MonetaryAmount tenEuro = Money.of(10, "EUR");
  
// convert 10 euro to us dollar
MonetaryAmount inDollar = tenEuro.with(dollarConversion); // "USD 12.537" (at the time writing)

CurrencyConversion은 MonetaryOperator 인터페이스도 구현한다는 점에 유의하세요. 다른 작업과 마찬가지로 MonetaryAmount.with() 메서드를 통해 호출할 수도 있습니다.

형식 지정 및 구문 분석

  MonetaryAmount可以通过MonetaryAmountFormat来与字符串进行解析/格式化。

// formatting by locale specific formats
MonetaryAmountFormat germanFormat = MonetaryFormats.getAmountFormat(Locale.GERMANY);
MonetaryAmountFormat usFormat = MonetaryFormats.getAmountFormat(Locale.CANADA);
  
MonetaryAmount amount = Money.of(12345.67, "USD");
  
String usFormatted = usFormat.format(amount); // "USD12,345.67"
String germanFormatted = germanFormat.format(amount); // 12.345,67 USD
  
// A MonetaryAmountFormat can also be used to parse MonetaryAmounts from strings
MonetaryAmount parsed = germanFormat.parse("12,4 USD");

可以通过AmountFormatQueryBuilder来生成自定义的格式。

// Creating a custom MonetaryAmountFormat
MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat(
    AmountFormatQueryBuilder.of(Locale.US)
        .set(CurrencyStyle.NAME)
        .set("pattern", "00,00,00,00.00 ¤")
        .build());
  
// results in "00,01,23,45.67 US Dollar"
String formatted = customFormat.format(amount);

注意,这里的¤符号在模式串中是作为货币的占位符。

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.