जावा में पैसे के लिए किस प्रकार के डेटा का उपयोग करना है? [बन्द है]


183

जावा में पैसे के लिए आपको किस प्रकार का डेटा इस्तेमाल करना चाहिए?


2
यह निर्भर करता है कि आप क्या ऑपरेशन करने जा रहे हैं। कृपया अधिक जानकारी प्रदान करें।
eversor

@ क्या आप मुझे बता सकते हैं कि विभिन्न ऑपरेशनों के लिए किस प्रकार के डेटा का उपयोग किया जाना चाहिए?
नवजात शिशु

1
गणना कर रहा हूँ जो मुझे सही ढंग से सेंट का प्रतिनिधित्व करने की आवश्यकता है।
नवजात शिशु

क्या आप अपने ऐप को संभालने के लिए सबसे बड़ी राशि चुकाने में सक्षम हैं? और, आपकी गणना, क्या वे सरल (एडिशन आदि) या अधिक जटिल वित्तीय संचालन करने जा रहे हैं?
eversor

जवाबों:


133

जावा में Currencyवर्ग है जो आईएसओ 4217 मुद्रा कोड का प्रतिनिधित्व करता है। BigDecimalमुद्रा दशमलव मानों का प्रतिनिधित्व करने के लिए सबसे अच्छा प्रकार है।

जोडा मनी ने पैसे का प्रतिनिधित्व करने के लिए एक पुस्तकालय प्रदान किया है।


5
हम इसके बजाय फ्लोट या डबल का उपयोग क्यों नहीं कर सकते हैं?
एरान मोराद

20
@ बोरत सगदयेव यही कारण है । इसके अलावा, आप उल्लेख कर सकते हैं इस
बुहके सिंडी

2
@ बोरैट: यदि आप जानते हैं कि आप क्या कर रहे हैं, तो पीटर लॉरी का यह लेख देखें । लेकिन ऐसा लगता है कि BigDecimals का उपयोग करने के लिए सभी राउंडिंग करने के लिए कम से कम एक बड़ी परेशानी है।
नाथन ह्यूजेस

35
"यदि मेरे पास हर बार के लिए एक पैसा होता है तो मैंने किसी को फ़्लोट का उपयोग मुद्रा को स्टोर करने के लिए किया है, मेरे पास $ 999.997634 है" - बिल कार्विन
कॉलिन क्रॉल

36

आप मुद्रा और मुद्रा एपीआई (जेएसआर 354) का उपयोग कर सकते हैं । आप इस API का उपयोग कर सकते हैं, बशर्ते आप अपनी परियोजना में उपयुक्त निर्भरता जोड़ दें।

जावा 8 के लिए, आपके लिए एक निर्भरता के रूप में निम्नलिखित संदर्भ कार्यान्वयन जोड़ें pom.xml:

<dependency>
    <groupId>org.javamoney</groupId>
    <artifactId>moneta</artifactId>
    <version>1.0</version>
</dependency>

यह निर्भरता javax.money:money-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") );
    }
}

क्या क्रमांकन और DB में बचत के बारे में? तार भेजने के लिए किस प्रारूप का उपयोग किया जाना चाहिए?
पावेल स्ज़ेसुर

1
मेरा मानना ​​है कि ओरेकल जावा 9 में जावा मनी सहित फिर से समर्पित है। वास्तव में एक शर्म की बात है। लेकिन शानदार जवाब। हम अभी भी इसका उपयोग मावेन के साथ कर सकते हैं
बोरजब

3
क्या आपके पास जावा 9 में जावा मनी सहित खिलाफ ओरेकल के लिए एक स्रोत है?
अब्दुल

26

सबसे छोटा मूल्य संभव का प्रतिनिधित्व करने वाला एक अभिन्न प्रकार। दूसरे शब्दों में आपके कार्यक्रम को डॉलर / यूरो में नहीं, सेंट में सोचना चाहिए।

यह आपको गुई में डॉलर / यूरो में वापस अनुवाद करने से नहीं रोकना चाहिए।


इस बात को ध्यान में रखें कि धन की मात्रा int
eversor

5
@ वेयरर्स को 20 मिलियन डॉलर से अधिक की आवश्यकता होगी जो कि ज्यादातर ऐप की जरूरत नहीं होगी अगर वे लंबे समय तक काम करेंगे तो यह भी पर्याप्त नहीं होगा क्योंकि हमारे गोवेन्मेंट भी ओवरऑल करने के लिए पर्याप्त मोल संभालते हैं
शाफ़्ट फ्रीक

4
@ratchetfreak शायद एक लंबे समय का उपयोग करने के लिए बेहतर है।
ट्रिगमेंडर्स

4
कई बैंक हर दिन $ 20,000,000 की बड़ी रकम संभालते हैं। यह येन जैसी मुद्राओं की बड़ी विनिमय दरों के साथ डॉलर तक नहीं ले जाता है। पूर्णांक समस्याओं से बचने के लिए पूर्णांक प्रकार सर्वोत्तम हो सकते हैं, हालांकि वे ब्याज और विनिमय दर की गणना के साथ गड़बड़ हो जाते हैं। हालांकि, आवेदन के आधार पर, आपको 64-बिट पूर्णांक प्रकार की आवश्यकता हो सकती है।
अल्काइमर

आदर्श रूप से माइक्रोडोलर, वास्तव में, जैसे कि अगर आप $ 10/3 करते हैं तो गोलाई त्रुटि (3333.3 => 3333.0) अंतिम मूल्य को उतना प्रभावित नहीं करती है (इस मामले में यह वास्तविक मूल्य को बिल्कुल प्रभावित नहीं करता है, हालांकि यह है यह मान लेना खतरनाक है कि यह कभी नहीं होगा)। यह विशेष रूप से महत्वपूर्ण है यदि आप अपने उपयोगकर्ता द्वारा परिणाम देखने से पहले एक पंक्ति में बहुत सारी गणना कर रहे हैं, क्योंकि गोलाई की त्रुटियां यौगिक होंगी।
क्रिस ब्राउन

13

BigDecimal का उपयोग किया जा सकता है, फ्लोट या डबल का उपयोग न करने की अच्छी व्याख्या यहाँ देखी जा सकती है: मुद्रा का प्रतिनिधित्व करने के लिए डबल या फ्लोट का उपयोग क्यों नहीं किया जाता है ?


11

JSR 354: मुद्रा और मुद्रा एपीआई

JSR 354 धन और मुद्रा के साथ व्यापक गणना का प्रतिनिधित्व, परिवहन और प्रदर्शन के लिए एक एपीआई प्रदान करता है। आप इसे इस लिंक से डाउनलोड कर सकते हैं:

JSR 354: मुद्रा और मुद्रा एपीआई डाउनलोड

विनिर्देशन में निम्नलिखित चीजें शामिल हैं:

  1. मौद्रिक राशि और मुद्राओं को संभालने के लिए एक एपीआई
  2. विनिमेय कार्यान्वयन का समर्थन करने के लिए एपीआई
  3. कार्यान्वयन वर्गों के उदाहरण बनाने के लिए फैक्टरियाँ
  4. मौद्रिक राशियों की गणना, रूपांतरण और प्रारूपण के लिए कार्यशीलता
  5. जावा एपीआई मनी और मुद्राओं के साथ काम करने के लिए, जिसे जावा 9 में शामिल करने की योजना है।
  6. सभी विनिर्देश वर्ग और इंटरफेस javax.money। * पैकेज में स्थित हैं।

जेएसआर 354 का नमूना उदाहरण: मुद्रा और मुद्रा एपीआई:

एक मोनोमाउंट बनाने और कंसोल पर इसे प्रिंट करने का एक उदाहरण इस तरह दिखता है ::

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 मौद्रिक गणना के साथ गणना का भी समर्थन करता है:

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 = 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

जब मोनेटअमाउंट के संग्रह के साथ काम करते हैं, तो फ़िल्टरिंग, सॉर्टिंग और ग्रुपिंग के लिए कुछ अच्छी उपयोगिता विधियां उपलब्ध हैं।

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

संसाधन:

JSR 354 के साथ जावा में पैसे और मुद्राएं संभालना

जावा 9 मनी और मुद्रा एपीआई (जेएसआर 354) में खोज

इसे भी देखें: JSR 354 - मुद्रा और धन


यह सब अच्छा है, लेकिन जैसा कि फेडेरिको ने ऊपर सुझाव दिया था, यह बिगडीकल की तुलना में धीमी दिखती है :-)) केवल बुरा मजाक है, लेकिन मैं इसे 1 साल बाद अब परीक्षा दूंगा ...
केंसई

6

मौद्रिक मूल्यों का प्रतिनिधित्व करने के लिए आपको बिगडेसिमल का उपयोग करना चाहिए । यह आपको कई प्रकार के राउंडिंग मोड्स का उपयोग करने की अनुमति देता है , और वित्तीय अनुप्रयोगों में, राउंडिंग मोड अक्सर एक कठिन आवश्यकता होती है जो कानून द्वारा भी अनिवार्य हो सकती है।



6

मैंने प्रदर्शन के मामले में बिगडेसीमल के खिलाफ मोनेटा (जावा मुद्रा जेएसआर 354 कार्यान्वयन) की तुलना करने के लिए एक माइक्रोबेनमार्क (जेएमएच) किया है।

हैरानी की बात है कि मोनेटा की तुलना में बिगडेसिमल का प्रदर्शन बेहतर है। मैंने निम्नलिखित मोनेटा विन्यास का उपयोग किया है:

org.javamoney.moneta.Money.defaults.preaches = 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

अगर मुझे कुछ याद आ रहा है तो कृपया मुझे सुधारने के लिए स्वतंत्र महसूस करें


दिलचस्प है, मैं JDK9 पर नवीनतम सामान के साथ एक ही परीक्षा चलाऊंगा
kensai

4

साधारण मामले (एक मुद्रा) के लिए यह पर्याप्त है Integer/ Long। सेंट (...) या सौवें / हजारवें सेंट के पैसे रखें (किसी भी सटीक जो आपको निर्धारित विभक्त के साथ चाहिए)


3

BigDecimal मुद्रा के लिए उपयोग करने के लिए सबसे अच्छा डेटा प्रकार है।

मुद्रा के लिए बहुत सारे कंटेनर हैं, लेकिन वे सभी अंतर्निहित डेटा प्रकार के रूप में BigDecimal का उपयोग करते हैं। आप BigDecimal के साथ गलत नहीं करेंगे, शायद BigDecimal.ROUND_HALF_EVEN गोलाई का उपयोग कर रहे हैं।


2

मुझे टाइनी टाइप्स का इस्तेमाल करना पसंद है जो या तो एक डबल, बिगडेक्मल को लपेटेगा, या पिछले उत्तरों के रूप में सुझाव देगा। (मैं तब तक एक डबल का उपयोग करूंगा जब तक कि सटीक समस्याएं फसल न लें)।

एक टिनी टाइप आपको सुरक्षा प्रदान करता है ताकि आप दूसरे डबल्स के साथ एक डबल पैसा न दें।


6
जबकि मुझे भी छोटे प्रकार पसंद हैं, आपको मौद्रिक मूल्य को संग्रहीत करने के लिए कभी भी डबल का उपयोग नहीं करना चाहिए ।
orien
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.