Java에서 돈을 위해 사용할 데이터 유형은 무엇입니까? [닫은]
Java에서 어떤 데이터 유형을 돈으로 사용해야합니까?
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
MonetaryAmount 콜렉션으로 작업 할 때 필터링, 정렬 및 그룹화를위한 유용한 유틸리티 메소드를 사용할 수 있습니다.
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
자원:
Handling money and currencies in Java with JSR 354
Looking into the Java 9 Money and Currency API (JSR 354)
See Also: JSR 354 - Currency and Money
I would use Joda Money
It's still at version 0.6 but looks very promising
I have done a microbenchmark (JMH) to compare Moneta (java currency JSR 354 implementation) against BigDecimal in terms of performance.
Surprisingly, BigDecimal performance seems to be better than moneta's. I have used following moneta config:
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);
}
}
Resulting in
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
Please feel free to correct me if i'm missing something
You should use BigDecimal to represent monetary values .It allows you to use a variety of rounding modes, and in financial applications, the rounding mode is often a hard requirement that may even be mandated by law.
For simple case (one currency) it'is enough Integer
/Long
. Keep money in cents (...) or hundredth / thousandth of cents (any precision you need with fixed divider)
BigDecimal is the best data type to use for currency.
There are a whole lot of containers for currency, but they all use BigDecimal as the underlying data type. You won't go wrong with BigDecimal, probably using BigDecimal.ROUND_HALF_EVEN rounding.
I like using Tiny Types which would wrap either a double, BigDecimal, or int as previous answers have suggested. (I would use a double unless precision problems crop up).
A Tiny Type gives you type safety so you don't confused a double money with other doubles.
참고URL : https://stackoverflow.com/questions/8148684/what-data-type-to-use-for-money-in-java
'IT story' 카테고리의 다른 글
Java에서 열거 형의 이름 지정 : 단수 또는 복수? (0) | 2020.05.29 |
---|---|
복제 된 원본 저장소와 원본 원격 저장소 간 git diff (0) | 2020.05.29 |
MongoDB에서 findAndModify와 업데이트의 차이점은 무엇입니까? (0) | 2020.05.29 |
FirebaseInstanceIdService는 더 이상 사용되지 않습니다 (0) | 2020.05.29 |
변하지 않는 문화 란 무엇입니까? (0) | 2020.05.29 |