BigDecimal: per utilizzare new o valueOf


97

Mi sono imbattuto in due modi per ottenere un oggetto BigDecimal da una doppia d.

1. new BigDecimal(d)
2. BigDecimal.valueOf(d)

Quale sarebbe un approccio migliore? ValueOf creerebbe un nuovo oggetto?

In generale (non solo BigDecimal), cosa è consigliato: new o valueOf?

Grazie.


9
In generale si preferisce valueOf (perché può evitare di creare nuovi oggetti riutilizzando istanze "popolari"), ma nel caso di BigDecimals e double, sfortunatamente, i due metodi producono risultati diversi, quindi devi scegliere quale ti serve.
Thilo

Risposte:


160

Queste sono due domande separate: "Per cosa dovrei usare BigDecimal?" e "Cosa devo fare in generale?"

Per BigDecimal: questo è un po 'complicato, perché non fanno la stessa cosa . BigDecimal.valueOf(double)utilizzerà la rappresentazione canonicaString del doublevalore passato per istanziare l' BigDecimaloggetto. In altre parole: il valore BigDecimaldell'oggetto sarà quello che vedi quando lo fai System.out.println(d).

Se si utilizza new BigDecimal(d)tuttavia, BigDecimalproverà a rappresentare il doublevalore nel modo più accurato possibile . Questo di solito si tradurrà in molte più cifre memorizzate di quanto desideri. A rigor di termini, è più corretto di valueOf(), ma è molto meno intuitivo.

C'è una bella spiegazione di questo nel JavaDoc:

I risultati di questo costruttore possono essere alquanto imprevedibili. Si potrebbe supporre che la scrittura new BigDecimal(0.1)in Java crei un BigDecimalche è esattamente uguale a 0.1 (un valore non graduato di 1, con una scala di 1), ma in realtà è uguale a 0.1000000000000000055511151231257827021181583404541015625. Questo perché 0.1 non può essere rappresentato esattamente come a double(o, del resto, come frazione binaria di qualsiasi lunghezza finita). Pertanto, il valore che viene passato al costruttore non è esattamente uguale a 0,1, nonostante le apparenze.

In generale, se il risultato è lo stesso (cioè non nel caso di BigDecimal, ma nella maggior parte degli altri casi), allora valueOf()dovrebbe essere preferito: può fare il caching di valori comuni (come visto su Integer.valueOf()) e può anche cambiare il comportamento del caching senza il chiamante deve essere cambiato. newsarà sempre un'istanza di un nuovo valore, anche se non necessario (esempio migliore: new Boolean(true)vs Boolean.valueOf(true)).


Questo spiega anche la mia domanda: stackoverflow.com/questions/15685705/…
Christian

3
@ Joachim, non era chiaro. È new BigDecimal()meglio di BigDecimal.valueOf()?
ryvantage

5
@ryvantage: se uno fosse rigorosamente migliore dell'altro, non ci sarebbe bisogno di entrambi e la mia risposta sarebbe molto più breve. Non fanno la stessa cosa, quindi non puoi classificarli in quel modo.
Joachim Sauer

2
@JoachimSauer, ok scusa avrei dovuto essere più specifico. Ti dispiacerebbe fornire un esempio di quando new BigDecimal()sarebbe preferibile e un esempio di quando BigDecimal.valueOf()sarebbe preferito?
ryvantage

@ryvantage: confronta i risultati di new BigDecimal(1.0/30.0);e BigDecimal.valueOf(1.0/30.0). Scopri quale risultato è effettivamente più vicino alla frazione numerica 1/30.
supercat

46

Se stai utilizzando i tuoi BigDecimaloggetti per memorizzare i valori di valuta, ti consiglio vivamente di NON includere valori doppi in nessun punto dei loro calcoli.

Come affermato in un'altra risposta, ci sono problemi di precisione noti con valori doppi e questi torneranno a perseguitarti.

Dopo averlo superato, la risposta alla tua domanda è semplice. Usa sempre il metodo del costruttore con il valore String come argomento del costruttore, poiché non esiste un valueOfmetodo per String.

Se vuoi una prova, prova quanto segue:

BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = new BigDecimal("0.01");
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);

Otterrai il seguente output:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

Vedi anche questa domanda correlata


5

Fondamentalmente valueOf (double val) fa solo questo:

return new BigDecimal(Double.toString(val));

Quindi -> sì, verrà creato un nuovo oggetto :).

In generale penso che dipenda dal tuo stile di codifica. Non mischerei valueOf e "new", se entrambi hanno lo stesso risultato.


7
Tecnicamente vero, ma : farà un'enorme differenza. valueOf()ha il comportamento più intuitivo , mentre new BigDecimal(d)ha quello più corretto . Prova entrambi e vedi la differenza.
Joachim Sauer

Tecnicamente falso. La parola chiave 'new' always crea sempre un nuovo oggetto mentre javadoc non dice se valueOf restituirà sempre un nuovo oggetto o meno. Non è così, non sempre. Ha alcuni valori nella cache quindi new BigDecimal(1) != new BigDecimal(1)maBigDecimal.valueOf(1) == BigDecimal.valueOf(1)
aalku

1
@user: sì, ma dal momento che BigDecimalè immutabile deve essere trattato allo stesso modo che i wrapper primitive ( Integer, Byte, ...) e Stringvengono trattati: identità di un oggetto non dovrebbe questione al codice, solo il valore dovrebbe avere importanza.
Joachim Sauer

@Joachim Giusto, ma quella cache interna è lì per un motivo. Troppe istanze uguali non necessarie di BigDecimal non sono una buona cosa da avere. E stavo rispondendo al dottor, Ha detto "verrà creato un nuovo oggetto"
aalku

3
@user: sì, è per questo che ho detto che valueOf()dovrebbe essere generalmente preferito. Ma nota che BigDecimal.valueOf(double)non esegue alcuna memorizzazione nella cache (e probabilmente non ne varrebbe la pena).
Joachim Sauer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.