Jaki jest najlepszy typ danych do wykorzystania dla pieniędzy w aplikacji Java?Jaki jest najlepszy typ danych, jakich należy używać dla pieniędzy w aplikacji Java?
Odpowiedz
Java ma Currency
klasę, która reprezentuje ISO 4217 kody walut. BigDecimal
to najlepszy typ do reprezentowania wartości dziesiętnych w walutach.
Joda Money dostarczył bibliotekę do reprezentowania pieniędzy.
Dlaczego nie możemy zamiast tego używać float lub double? –
@Borat Sagdiyev [To jest powód] (http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). Możesz również skorzystać z [this] (https://www.securecoding.cert.org/confluence/display/java/NUM04-J.+Do+not+use+useingpointpoint+numbers+if+precise+computation + jest + wymagany). –
@Borat: możesz, jeśli wiesz, co robisz, przeczytaj [ten artykuł] (http://vanillajava.blogspot.com/2011/08/double-your-money-again.html) Petera Lawrey'a. ale wydaje się co najmniej kłopotliwe, aby zrobić wszystkie zaokrąglenia, aby korzystać z BigDecimals. –
użyłbym Joda Money
To wciąż w wersji 0.6, ale wygląda bardzo obiecująco
BigDecimal jest najlepszy typ danych do wykorzystania na waluty.
Istnieje wiele kontenerów na waluty, ale wszystkie one używają BigDecimal jako podstawowego typu danych. Nie popełnisz błędu w BigDecimal, prawdopodobnie za pomocą zaokrąglania BigDecimal.ROUND_HALF_EVEN.
Należy użyć BigDecimal do reprezentowania wartości pieniężne .To pozwala na korzystanie z wielu trybówzaokrągleń, aw aplikacji finansowych, tryb zaokrąglania jest często trudne wymaganie , które mogą być nawet nakazane przez prawo .
Typ integralny reprezentujący najmniejszą możliwą wartość. Innymi słowy, twój program powinien myśleć w centach nie w dolarach/euro.
Nie powinno to powstrzymać cię przed tłumaczeniem gui z powrotem na dolary/euro.
Pamiętaj, że ilość pieniędzy może przekroczyć rozmiar int – eversor
@eversor, który potrzebowałby ponad 20 milionów dolarów, a większość aplikacji nie potrzebowałaby tak dużo, jeśli robią wystarczająco długo, ponieważ nawet nasze produkty nie wystarczą na tyle przepełnienie to –
@ratchetfreak Prawdopodobnie lepiej użyć długiego czasu. –
BigDecimal można stosować dobre wyjaśnienie dlaczego nie użyć Float lub Pokój można obejrzeć tutaj: Why not use Double or Float to represent currency?
Lubię używać Tiny Types, które będzie zawijać podwójne, BigDecimal lub int, jak sugerowały poprzednie odpowiedzi. (Chciałbym użyć podwójnego, chyba że pojawią się problemy z precyzją).
Tiny Type zapewnia bezpieczeństwo typu, dzięki czemu nie można pomylić podwójnych pieniędzy z innymi graczami.
Podczas gdy ja też lubię małe typy, powinieneś * Nigdy * używać podwójnego do przechowywania wartości pieniężnej. – orien
Możesz użyć Money and Currency API (JSR 354). Oczekuje się, że ten interfejs API będzie częścią środowiska Java 9. Możesz używać tego interfejsu API w języku Java 7 i Java 8, o ile dodasz odpowiednie zależności do projektu.
Dla Java 8, dodaj następującą implementację referencyjną 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 przechodni dodać javax.money:money-api
jako zależność.
Następnie można 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"));
}
}
A co z serializacją i zapisywaniem w db? Jakiego formatu należy użyć do przesyłania przez przewód? –
Wierzę, że Oracle odliczył againts, w tym Java Money w Javie 9. Naprawdę wstyd. Ale wspaniała odpowiedź. Nadal możemy używać go z Mavenem – borjab
Czy masz źródło dla Oracle decydujące przeciwko włączeniu Java Money w Java 9? – Abdull
Zrobiłem microbenchmark (JMH) porównać Moneta (Java waluty JSR 354 realizacji) przed BigDecimal pod względem wydajności.
Co zaskakujące, wydajność BigDecimal wydaje się lepsza niż moneta. I stosuje się następujące moneta konfiguracji:
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);
}
}
, 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
Prosimy o mnie poprawić, jeśli jestem czegoś brakuje
Interesujące, będę prowadził ten sam test z najnowszymi rzeczami na JDK9 – kensai
JSR 354: pieniądze i Waluta API
JSR 354 zapewnia interfejs API do reprezentowania, transportu i wykonywania kompleksowych obliczeń za pomocą pieniędzy i waluty. Można go pobrać z tego linku:
JSR 354: Money and Currency API Download
Specyfikacja składa się z następujących rzeczy:
- API do obsługi e. sol. kwoty pieniężne i waluty
- Apis wspierać wymiennymi realizacje
- Fabryki do tworzenia instancji klas realizacji
- funkcjonalności do obliczeń, konwersji i formatowania kwot pieniężnych
- Java API do pracy z pieniędzmi i waluty, która jest planowane do uwzględnienia w Javie 9.
- Wszystkie klasy specyfikacji i interfejsy znajdują się w pakiecie javax.money. *.
Przykładowe Przykłady JSR 354: Pieniądze i Waluta API:
Przykładem tworzenia MONETARYAMOUNT i drukowanie go do 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));
When przy użyciu referencyjnego API implementacji 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ż obliczeń 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 pozwalają dostępem przypisaną walutę, kwotę numeryczną, jego precyzja 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;
MonetaryAmounts można zaokrąglać za pomocą operatora zaokrąglającego:
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 z kolekcjami MonetaryAmounts dostępne są niektóre przydatne metody filtrowania, sortowania i grupowania.
operacjeList<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"));
klienta 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
zasoby:
Handling money and currencies in Java with JSR 354
Looking into the Java 9 Money and Currency API (JSR 354)
Zobacz także: JSR 354 - Currency and Money
Wszystko to jest miłe, ale jak sugerował Federico powyżej, wygląda na wolniejsze niż BigDecimal :-)), tylko jeden zły dowcip, ale dam mu test teraz 1 rok później. .. – kensai
W przypadku prostego przypadku (jedna waluta) wystarczy Integer
/Long
. Przechowuj pieniądze w centach (...) lub setnych/tysięcznych centów (każda precyzja, jakiej potrzebujesz, ze stałym rozdzielaczem)
- 1. Jaki typ danych XML powinienem użyć dla waluty/pieniędzy?
- 2. Jaki jest najlepszy typ danych dla walut w MySQL?
- 3. Najlepszy typ dla danych UTF-8?
- 4. Jaki jest najlepszy typ w języku Hack?
- 5. Jaki jest najlepszy typ danych SQL do przechowywania ciągu JSON?
- 6. jaki jest niepodpisany typ danych?
- 7. Jaki jest najlepszy sterownik Java dla dostępu mongodb?
- 8. Najlepszy sposób na zapisywanie danych w aplikacji Java?
- 9. Jaki jest najlepszy projekt do odpytywania modemu dla przychodzących danych?
- 10. Jaki jest najlepszy sposób na utrwalanie danych w aplikacji Java Desktop?
- 11. Jaki typ danych jest najlepszy do zapisywania obrazów w bazie danych?
- 12. Jaki jest typ danych dla hasła w PostgreSQL?
- 13. Z jakich interfejsów API Documentum należy korzystać?
- 14. Jaki jest "krótki" typ danych w C?
- 15. Jaki jest typ użytkownika facebook
- 16. Jaki jest najlepszy sposób przetestowania aplikacji szyny?
- 17. Jaki jest najlepszy serwer WWW dla aplikacji Ruby on Rails?
- 18. Jaki jest najlepszy framework serwisowy Java?
- 19. Jaki jest najlepszy sposób przechowywania danych obszaru dla przygody tekstowej?
- 20. jaki jest najlepszy sposób generowania fałszywych danych dla problemu klasyfikacji?
- 21. Jaki jest najlepszy stos Java SIP?
- 22. Jaki jest typ danych MLSLABEL Oracle?
- 23. jaki jest najlepszy typ kolekcji do zwrócenia w API
- 24. Typ danych SQL do użycia podczas wstawiania pieniędzy
- 25. Jaki jest najlepszy język skryptowy dla Unity3D
- 26. Jaki typ danych Java odpowiada typowi danych Oracle SQL NUMERIC?
- 27. Typ danych dla System.Version w serwerze sql
- 28. Jaki jest najlepszy sposób na spakowanie aplikacji Ruby on Rails?
- 29. Jaki jest najlepszy sposób na profilowanie bazy danych sqlserver 2005 dla wydajności?
- 30. Jaki jest najlepszy sposób przechowywania niepublicznych danych konfiguracyjnych w aplikacji .NET 4.0
Zależy od tego, jakie operacje zamierzasz wykonać. Proszę podać więcej informacji. – eversor
@eversor Czy możesz podać mi jaki typ danych powinien być używany do różnych operacji? – questborn
Wykonuję obliczenia, które wymagają dokładnego przedstawienia centów. – questborn