BigDecimal - para usar new o valueOf

97

Encontré dos formas de sacar el objeto BigDecimal de una doble d.

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

¿Cuál sería un mejor enfoque? ¿ValueOf crearía un nuevo objeto?

En general (no solo BigDecimal), ¿qué se recomienda: nuevo o valueOf?

Gracias.

Manish Mulani
fuente
9
En general, se prefiere valueOf (porque puede evitar la creación de nuevos objetos reutilizando instancias "populares"), pero en el caso de BigDecimals y double, desafortunadamente, los dos métodos producen resultados diferentes, por lo que debe elegir cuál necesita.
Thilo

Respuestas:

160

Esas son dos preguntas separadas: "¿Para qué debo usar BigDecimal?" y "¿Qué hago en general?"

Para BigDecimal: esto es un poco complicado, porque no hacen lo mismo . BigDecimal.valueOf(double)utilizará la representación canónicaString del doublevalor pasado para instanciar el BigDecimalobjeto. En otras palabras: el valor del BigDecimalobjeto será lo que vea cuando lo haga System.out.println(d).

new BigDecimal(d)Sin embargo, si utiliza , BigDecimalintentará representar el doublevalor con la mayor precisión posible . Esto generalmente dará como resultado que se almacenen muchos más dígitos de los que desea. Estrictamente hablando, es más correcto que valueOf(), pero es mucho menos intuitivo.

Hay una buena explicación de esto en JavaDoc:

Los resultados de este constructor pueden ser algo impredecibles. Se podría suponer que escribir new BigDecimal(0.1)en Java crea un valor BigDecimalexactamente igual a 0.1 (un valor sin escala de 1, con una escala de 1), pero en realidad es igual a 0.1000000000000000055511151231257827021181583404541015625. Esto se debe a que 0,1 no se puede representar exactamente como a double(o, para el caso, como una fracción binaria de cualquier longitud finita). Por tanto, el valor que se pasa al constructor no es exactamente igual a 0,1, a pesar de las apariencias.

En general, si el resultado es el mismo (es decir, no en el caso de BigDecimal, pero en la mayoría de los otros casos), entonces valueOf()debería preferirse: puede realizar el almacenamiento en caché de valores comunes (como se ve en Integer.valueOf()) e incluso puede cambiar el comportamiento de almacenamiento en caché sin la persona que llama debe cambiarse. siemprenew creará una instancia de un nuevo valor, incluso si no es necesario (mejor ejemplo: vs. ).new Boolean(true)Boolean.valueOf(true)

Joachim Sauer
fuente
Esto también explica mi pregunta: stackoverflow.com/questions/15685705/…
Christian
3
@Joachim, no estaba claro. Es new BigDecimal()mejor que BigDecimal.valueOf()?
Ryvantage
5
@ryvantage: si uno fuera estrictamente mejor que el otro, no habría necesidad de ambos y mi respuesta sería mucho más corta. No hacen lo mismo, por lo que no puede clasificarlos así.
Joachim Sauer
2
@JoachimSauer, está bien, lo siento, debería haber sido más específico. ¿Le importaría dar un ejemplo de cuándo new BigDecimal()sería preferible y un ejemplo de cuándo BigDecimal.valueOf()sería preferible?
Ryvantage
@ryvantage: compara los resultados de new BigDecimal(1.0/30.0);y BigDecimal.valueOf(1.0/30.0). Vea qué resultado está realmente más cerca de la fracción numérica 1/30.
supercat
46

Si está utilizando sus BigDecimalobjetos para almacenar valores de moneda, le recomiendo encarecidamente que NO incluya valores dobles en ningún lugar de sus cálculos.

Como se indica en otra respuesta, existen problemas de precisión conocidos con valores dobles y estos volverán a atormentarlo a lo grande.

Una vez que supere eso, la respuesta a su pregunta es simple. Utilice siempre el método del constructor con el valor String como argumento del constructor, ya que no hay ningún valueOfmétodo para String.

Si desea una prueba, intente lo siguiente:

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

Obtendrá el siguiente resultado:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

Vea también esta pregunta relacionada

DuncanKinnear
fuente
5

Básicamente valueOf (double val) solo hace esto:

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

Por lo tanto -> sí, se creará un nuevo objeto :).

En general, creo que depende de su estilo de codificación. No mezclaría valueOf y "new", si ambos son el mismo resultado.

DXTR66
fuente
7
Técnicamente cierto, pero hará una gran diferencia. valueOf()tiene el comportamiento más intuitivo , mientras que new BigDecimal(d)tiene el más correcto . Pruebe ambos y vea la diferencia.
Joachim Sauer
Técnicamente falso. La palabra clave 'new' always siempre crea un nuevo objeto mientras que el javadoc no dice si valueOf devolverá siempre un nuevo objeto o no. No siempre es así. Tiene algunos valores en el caché, new BigDecimal(1) != new BigDecimal(1)peroBigDecimal.valueOf(1) == BigDecimal.valueOf(1)
aalku
1
@user: sí, pero ya que BigDecimales inmutable debe ser tratado de la misma manera que los envoltorios primitivos ( Integer, Byte, ...) y Stringson tratados: la identidad del objeto no debe importar a su código, sólo el valor debería importar.
Joachim Sauer
@Joachim Correcto, pero ese caché interno está ahí por una razón. No es bueno tener demasiadas instancias iguales no necesarias de BigDecimal. Y estaba respondiendo al Dr., dijo "se creará un nuevo objeto"
aalku
3
@user: sí, es por eso que dije que valueOf()debería generalmente ser preferidos. Pero tenga en cuenta que BigDecimal.valueOf(double)no hace ningún almacenamiento en caché (y probablemente tampoco valdría la pena).
Joachim Sauer