답변:
Java에는 Currency
ISO 4217 통화 코드를 나타내는 클래스가 있습니다.
BigDecimal
통화 10 진수 값을 나타내는 데 가장 적합한 유형입니다.
Joda Money 는 돈을 대표하는 도서관을 제공했습니다.
Money and Currency API (JSR 354)를 사용할 수 있습니다 . 프로젝트에 적절한 종속성을 추가하면이 API를 사용할 수 있습니다.
Java 8의 경우 다음 참조 구현을 종속성에 추가하십시오 pom.xml
.
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.0</version>
</dependency>
이 종속성은 전 이적으로 종속성으로 추가 javax.money:money-api
됩니다.
그런 다음 API를 사용할 수 있습니다.
package com.example.money;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;
import java.util.Locale;
import javax.money.Monetary;
import javax.money.MonetaryAmount;
import javax.money.MonetaryRounding;
import javax.money.format.MonetaryAmountFormat;
import javax.money.format.MonetaryFormats;
import org.junit.Test;
public class MoneyTest {
@Test
public void testMoneyApi() {
MonetaryAmount eurAmount1 = Monetary.getDefaultAmountFactory().setNumber(1.1111).setCurrency("EUR").create();
MonetaryAmount eurAmount2 = Monetary.getDefaultAmountFactory().setNumber(1.1141).setCurrency("EUR").create();
MonetaryAmount eurAmount3 = eurAmount1.add(eurAmount2);
assertThat(eurAmount3.toString(), is("EUR 2.2252"));
MonetaryRounding defaultRounding = Monetary.getDefaultRounding();
MonetaryAmount eurAmount4 = eurAmount3.with(defaultRounding);
assertThat(eurAmount4.toString(), is("EUR 2.23"));
MonetaryAmountFormat germanFormat = MonetaryFormats.getAmountFormat(Locale.GERMAN);
assertThat(germanFormat.format(eurAmount4), is("EUR 2,23") );
}
}
가능한 가장 작은 값을 나타내는 정수 유형입니다. 다시 말해, 프로그램은 달러 / 유로가 아닌 센트 단위로 생각해야합니다.
이것은 GUI가 달러 / 유로로 다시 변환하는 것을 막지 않아야합니다.
BigDecimal을 사용할 수 있으며 Float 또는 Double을 사용하지 않는 이유에 대한 좋은 설명은 여기에서 볼 수 있습니다. Double 또는 Float를 사용하여 통화를 나타내지 않는 이유는 무엇입니까?
JSR 354 : 화폐 및 통화 API
JSR 354는 Money and Currency를 사용하여 포괄적 인 계산을 표현, 전송 및 수행하기위한 API를 제공합니다. 이 링크에서 다운로드 할 수 있습니다.
사양은 다음과 같이 구성됩니다.
- 화폐 금액 및 통화 처리를위한 API
- 상호 교환 가능한 구현을 지원하는 API
- 구현 클래스의 인스턴스를 작성하기위한 팩토리
- 금액 계산, 변환 및 서식 지정 기능
- Java 9에 포함될 예정인 Money and Currencies 작업을위한 Java API
- 모든 사양 클래스와 인터페이스는 javax.money. * 패키지에 있습니다.
JSR 354의 샘플 예 : Money and Currency API :
MonetaryAmount를 작성하여 콘솔에 인쇄하는 예는 다음과 같습니다.
MonetaryAmountFactory<?> amountFactory = Monetary.getDefaultAmountFactory();
MonetaryAmount monetaryAmount = amountFactory.setCurrency(Monetary.getCurrency("EUR")).setNumber(12345.67).create();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
참조 구현 API를 사용할 때 필요한 코드는 훨씬 간단합니다.
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
API는 MonetaryAmounts를 사용한 계산도 지원합니다.
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));
통화 단위 및 통화 금액
// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);
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;
반올림 연산자를 사용하여 금액을 반올림 할 수 있습니다.
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
MonetaryAmounts 콜렉션으로 작업 할 때 필터링, 정렬 및 그룹화를위한 유용한 유틸리티 메소드를 사용할 수 있습니다.
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"));
사용자 정의 통화 금액 조작
// 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
자원:
Java 9 Money and Currency API 살펴보기 (JSR 354)
다음 사항도 참조 : JSR 354-통화 및 돈
Joda Money를 사용하겠습니다
여전히 버전 0.6이지만 매우 유망한 것으로 보입니다.
성능 측면에서 Moneta (Java 통화 JSR 354 구현)와 BigDecimal을 비교하기 위해 마이크로 벤치 마크 (JMH)를 수행했습니다.
놀랍게도 BigDecimal 성능은 moneta보다 우수합니다. 다음 moneta 구성을 사용했습니다.
org.javamoney.moneta.Money.defaults.precision = 19 org.javamoney.moneta.Money.defaults.roundingMode = HALF_UP
package com.despegar.bookedia.money;
import org.javamoney.moneta.FastMoney;
import org.javamoney.moneta.Money;
import org.openjdk.jmh.annotations.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.concurrent.TimeUnit;
@Measurement(batchSize = 5000, iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 2)
@Threads(value = 1)
@Fork(value = 1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
public class BigDecimalBenchmark {
private static final Money MONEY_BASE = Money.of(1234567.3444, "EUR");
private static final Money MONEY_SUBSTRACT = Money.of(232323, "EUR");
private static final FastMoney FAST_MONEY_SUBSTRACT = FastMoney.of(232323, "EUR");
private static final FastMoney FAST_MONEY_BASE = FastMoney.of(1234567.3444, "EUR");
MathContext mc = new MathContext(10, RoundingMode.HALF_UP);
@Benchmark
public void bigdecimal_string() {
new BigDecimal("1234567.3444").subtract(new BigDecimal("232323")).multiply(new BigDecimal("3.4"), mc).divide(new BigDecimal("5.456"), mc);
}
@Benchmark
public void bigdecimal_valueOf() {
BigDecimal.valueOf(12345673444L, 4).subtract(BigDecimal.valueOf(232323L)).multiply(BigDecimal.valueOf(34, 1), mc).divide(BigDecimal.valueOf(5456, 3), mc);
}
@Benchmark
public void fastmoney() {
FastMoney.of(1234567.3444, "EUR").subtract(FastMoney.of(232323, "EUR")).multiply(3.4).divide(5.456);
}
@Benchmark
public void money() {
Money.of(1234567.3444, "EUR").subtract(Money.of(232323, "EUR")).multiply(3.4).divide(5.456);
}
@Benchmark
public void money_static(){
MONEY_BASE.subtract(MONEY_SUBSTRACT).multiply(3.4).divide(5.456);
}
@Benchmark
public void fastmoney_static() {
FAST_MONEY_BASE.subtract(FAST_MONEY_SUBSTRACT).multiply(3.4).divide(5.456);
}
}
를 야기하는
Benchmark Mode Cnt Score Error Units
BigDecimalBenchmark.bigdecimal_string thrpt 10 479.465 ± 26.821 ops/s
BigDecimalBenchmark.bigdecimal_valueOf thrpt 10 1066.754 ± 40.997 ops/s
BigDecimalBenchmark.fastmoney thrpt 10 83.917 ± 4.612 ops/s
BigDecimalBenchmark.fastmoney_static thrpt 10 504.676 ± 21.642 ops/s
BigDecimalBenchmark.money thrpt 10 59.897 ± 3.061 ops/s
BigDecimalBenchmark.money_static thrpt 10 184.767 ± 7.017 ops/s
내가 빠진 것이 있으면 자유롭게 고쳐주세요
간단한 경우 (한 통화)면 충분합니다 Integer
/ Long
. 센트 (...) 또는 백분의 1 / 센트 (돈을 고정 분배기로 필요한 정밀도)로 유지하십시오