Jakiego typu danych użyć za pieniądze w Javie? [zamknięte]
chcesz poprawić to pytanie? Zaktualizuj pytanie, aby mogło być odpowiedź z faktami i cytatami przez edytując ten post .
Zamknięte 2 lata temu .
Popraw to pytanieJakiego typu danych należy używać za pieniądze w Javie?
11 answers
Java ma Currency
klasa, która reprezentuje kody walut ISO 4217.
BigDecimal
jest najlepszym typem do reprezentowania wartości dziesiętnych waluty.
Joda Money udostępniła bibliotekę do reprezentowania pieniędzy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-16 15:08:08
Możesz użyć Money and Currency API (JSR 354) . Możesz użyć tego API, pod warunkiem, że dodasz odpowiednie zależności do swojego projektu.
W Javie 8 dodaj następującą implementację odniesienia jako zależność do swojego pom.xml
:
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.0</version>
</dependency>
Ta zależność będzie przejściowo dodawać javax.money:money-api
jako zależność.
Możesz następnie użyć 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") );
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-13 10:53:37
Typ całkowy reprezentujący najmniejszą możliwą wartość. Innymi słowy, twój program powinien myśleć w centach, a nie w dolarach / euro.
Nie powinno to przeszkodzić w przetłumaczeniu gui na dolary / euro.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-02 22:49:51
BigDecimal może być używany, dobre wyjaśnienie dlaczego nie używać Float lub Double można zobaczyć tutaj: Dlaczego nie używać Double lub Float do reprezentowania waluty?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:26
JSR 354: API pieniądza i waluty
JSR 354 zapewnia API do reprezentowania, transportu i wykonywania kompleksowych obliczeń z użyciem pieniędzy i waluty. Możesz go pobrać z tego linku:
JSR 354: pieniądze i waluty API Pobierz
Specyfikacja składa się z następujących rzeczy:
- API do obsługi np. kwot pieniężnych i walut
- API obsługujące wymienne implementacje
- fabryk do tworzenia instancji klas implementacji
- funkcjonalność do obliczania, przeliczania i formatowania kwot pieniężnych
- Java API do pracy z pieniędzmi i walutami, które planowane jest włączenie do Java 9.
- wszystkie klasy specyfikacji i interfejsy znajdują się w javax.pieniądze.* pakiet.
Przykładowe przykłady JSR 354: pieniądze i waluta API:
Przykład utworzenia MonetaryAmount i wydrukowania go na konsoli wygląda następująco:
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));
Przy użyciu reference implementation API niezbędny kod jest znacznie prostszy:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
API obsługuje również obliczenia z MonetaryAmounts:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));
CurrencyUnit i MonetaryAmount
// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);
MonetaryAmount ma różne metody, które umożliwiają dostęp do przypisanej waluty, kwoty liczbowej, jej dokładności i więcej:
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;
Kwoty monetarne mogą być zaokrąglane za pomocą operatora zaokrąglania:
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
Podczas pracy ze zbiorami MonetaryAmounts, dostępne są pewne ładne metody użytkowe do filtrowania, sortowania i grupowania.
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"));
Custom MonetaryAmount operations
// 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
Zasoby:
Obsługa pieniędzy i walut w Javie za pomocą JSR 354
Przeglądanie Java 9 Money and Currency API (JSR 354)
Zobacz: JSR 354-waluta i pieniądze
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-07 07:01:13
Powinieneś używać BigDecimal do reprezentowania wartości pieniężnych. pozwala on na użycie różnych trybów zaokrąglania , a w aplikacji finansowych, tryb zaokrąglania jest często trudnym wymogiem to może być nawet nakazane przez prawo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 08:34:22
Użyłabym Joda Money
Jest nadal w wersji 0.6, ale wygląda bardzo obiecująco
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-16 15:08:19
Zrobiłem mikrobenchmark (JMH), aby porównać Moneta (Java currency JSR 354 implementation) z BigDecimal pod względem wydajności.
O dziwo, wydajność BigDecimal wydaje się być lepsza niż moneta. Wykorzystałem następujący config moneta:Org.javamoney.moneta.Pieniądze.domyślne.precyzja=19 org.javamoney.moneta.Pieniądze.domyślne.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);
}
}
W wyniku
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
Proszę o poprawienie mnie, jeśli coś mi umyka
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-29 12:58:17
Dla prostego przypadku (jednej waluty) wystarczy int
/long
.
Przechowywać pieniądze w centach (...) lub setna / tysięczna centów (Dowolna precyzja potrzebna ze stałym dzielnikiem)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-24 08:28:49
BigDecimal jest najlepszym typem danych do wykorzystania dla waluty.
Istnieje wiele kontenerów na waluty, ale wszystkie używają BigDecimal jako podstawowego typu danych. Nie pomylisz się z BigDecimal, prawdopodobnie używając BigDecimal.ROUND_HALF_EVEN zaokrąglenie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 08:34:19
Lubię używać małych typów, które owijałyby albo podwójny, BigDecimal, albo int, jak sugerowały poprzednie odpowiedzi. (Użyłbym podwójnego, chyba że pojawią się problemy z precyzją).
Mały Typ daje Ci bezpieczeństwo typu, więc nie pomylisz podwójnych pieniędzy z innymi sobowtórami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 11:58:40