Jenis data apa yang harus Anda gunakan untuk uang di Jawa?
Jenis data apa yang harus Anda gunakan untuk uang di Jawa?
Jawaban:
Java memiliki Currency
kelas yang mewakili kode mata uang ISO 4217.
BigDecimal
adalah jenis terbaik untuk mewakili nilai desimal mata uang.
Joda Money telah menyediakan perpustakaan untuk mewakili uang.
Anda dapat menggunakan API Uang dan Mata Uang (JSR 354) . Anda dapat menggunakan API ini di, asalkan Anda menambahkan dependensi yang sesuai untuk proyek Anda.
Untuk Java 8, tambahkan implementasi referensi berikut sebagai ketergantungan pada Anda pom.xml
:
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.0</version>
</dependency>
Ketergantungan ini akan ditambahkan javax.money:money-api
secara positif sebagai ketergantungan.
Anda kemudian dapat menggunakan 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") );
}
}
Tipe integral yang mewakili nilai sekecil mungkin. Dengan kata lain program Anda harus berpikir dalam sen bukan dalam dolar / euro.
Ini seharusnya tidak menghentikan Anda dari meminta gui menerjemahkannya kembali ke dolar / euro.
BigDecimal dapat digunakan, penjelasan yang baik tentang mengapa tidak menggunakan Float atau Double dapat dilihat di sini: Mengapa tidak menggunakan Double atau Float untuk mewakili mata uang?
JSR 354: API Uang dan Mata Uang
JSR 354 menyediakan API untuk mewakili, mengangkut, dan melakukan perhitungan komprehensif dengan Uang dan Mata Uang. Anda dapat mengunduhnya dari tautan ini:
JSR 354: Unduhan API Uang dan Mata Uang
Spesifikasi terdiri dari hal-hal berikut:
- API untuk penanganan misalnya jumlah uang dan mata uang
- API untuk mendukung implementasi yang dapat dipertukarkan
- Pabrik untuk membuat instance dari kelas implementasi
- Fungsi untuk perhitungan, konversi, dan pemformatan jumlah uang
- API Java untuk bekerja dengan Uang dan Mata Uang, yang rencananya akan dimasukkan dalam Java 9.
- Semua kelas spesifikasi dan antarmuka terletak di paket javax.money. *.
Contoh Contoh JSR 354: API Uang dan Mata Uang:
Contoh membuat MonetaryAmount dan mencetaknya ke konsol terlihat seperti ini ::
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));
Saat menggunakan API implementasi referensi, kode yang diperlukan jauh lebih sederhana:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
API juga mendukung perhitungan dengan MonetaryAmounts:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));
CurrencyUnit dan MonetaryAmount
// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);
MonetaryAmount memiliki berbagai metode yang memungkinkan mengakses mata uang yang ditetapkan, jumlah numerik, ketepatannya, dan lainnya:
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;
Jumlah Moneter dapat dibulatkan menggunakan operator pembulatan:
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
Saat bekerja dengan koleksi MonetaryAmounts, beberapa metode utilitas yang bagus untuk memfilter, menyortir, dan mengelompokkan tersedia.
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"));
Operasi MonetaryAmount khusus
// 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
Sumber:
Menangani uang dan mata uang di Jawa dengan JSR 354
Melihat ke dalam Java 9 Money and Currency API (JSR 354)
Lihat Juga: JSR 354 - Mata Uang dan Uang
Anda harus menggunakan BigDecimal untuk mewakili nilai moneter. Ini memungkinkan Anda untuk menggunakan berbagai mode pembulatan , dan dalam aplikasi keuangan, mode pembulatan seringkali merupakan persyaratan keras yang bahkan mungkin diamanatkan oleh hukum.
Saya akan menggunakan Joda Money
Itu masih di versi 0.6 tetapi terlihat sangat menjanjikan
Saya telah melakukan microbenchmark (JMH) untuk membandingkan Moneta (implementasi JSR 354 mata uang java) dengan BigDecimal dalam hal kinerja.
Anehnya, kinerja BigDecimal tampaknya lebih baik daripada moneta. Saya telah menggunakan konfigurasi moneta berikut:
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);
}
}
Yang menghasilkan
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
Silakan koreksi saya jika saya kehilangan sesuatu
Untuk kasus sederhana (satu mata uang) sudah cukup Integer
/ Long
. Simpan uang dalam sen (...) atau seperseratus / seperseribu sen (presisi apa pun yang Anda butuhkan dengan pembagi tetap)
BigDecimal adalah tipe data terbaik yang digunakan untuk mata uang.
Ada banyak wadah untuk mata uang, tetapi mereka semua menggunakan BigDecimal sebagai tipe data yang mendasarinya. Anda tidak akan salah dengan BigDecimal, mungkin menggunakan BigDecimal.ROUND_HALF_EVEN pembulatan.
Saya suka menggunakan Tiny Type yang akan membungkus ganda, BigDecimal, atau int seperti jawaban sebelumnya telah menyarankan. (Saya akan menggunakan ganda kecuali masalah presisi muncul).
Tipe Tiny memberi Anda keamanan tipe sehingga Anda tidak bingung dengan uang ganda dengan ganda lainnya.