BigDecimal equals () contro compareTo ()


157

Considera la semplice classe di test:

import java.math.BigDecimal;

/**
 * @author The Elite Gentleman
 *
 */
public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BigDecimal x = new BigDecimal("1");
        BigDecimal y = new BigDecimal("1.00");
        System.out.println(x.equals(y));
        System.out.println(x.compareTo(y) == 0 ? "true": "false");
    }

}

Puoi (consapevolmente) dire che xè uguale a y(non riferimento all'oggetto), ma quando esegui il programma, il seguente risultato mostra:

false
true

Domanda: Qual è la differenza tra compareTo()e equals()in BigDecimalciò che compareTopuò determinare che xè uguale a y?

PS: Vedo che BigDecimal ha un inflate()metodo sul equals()metodo. Cosa fa inflate()effettivamente?


1
Annuncio inflate(): non fa parte dell'API pubblica perché manipola solo la rappresentazione interna e non ha effetti visibili all'esterno. Quindi, a meno che tu non voglia davvero studiare l'implementazione BigDecimalapprofondita, ti suggerirei di ignorare questo metodo.
Joachim Sauer,

Una breve spiegazione e frammenti di codice sorgente possono essere trovati qui
xenteros

Risposte:


224

La risposta è nel JavaDoc del equals()metodo :

Diversamente compareTo, questo metodo considera due BigDecimaloggetti uguali solo se sono uguali in valore e scala (quindi 2.0 non è uguale a 2,00 se confrontato con questo metodo).

In altre parole: equals()controlla se gli BigDecimaloggetti sono esattamente gli stessi in ogni aspetto. compareTo()"solo" confronta il loro valore numerico.

Quanto al perché equals() si comporti in questo modo, a questa domanda SO è stata data risposta .


24
Questa è una parte molto complicata di BigDecimalse non leggi attentamente JavaDoc. :) - Abbiamo ottenuto alcuni strani bug da questo fino a quando non abbiamo capito la differenza.
Thomas,

3
Molte parti dell'API standard si comportano in modo "non intuitivo", quando la cosa intuitiva non sarebbe corretta. BigDecimalè una cosa del genere. Pertanto si dovrebbe sempre controllare JavaDoc. Almeno una volta scoperto che sta succedendo qualcosa di strano.
Joachim Sauer,

7
Divertente. Dopo aver letto la tua risposta, ho appena controllato Comparable e afferma che la coerenza con uguali "è fortemente consigliata (ma non obbligatoria)"
SJuan76


8
@StephenC Penso che sia errato che questa incoerenza esista.
Matt R

1

Vedo che BigDecimal ha un metodo inflate () sul metodo equals (). Cosa fa effettivamente infllate ()?

Fondamentalmente, inflate()chiama BigInteger.valueOf(intCompact)se necessario, ovvero crea il valore non scalato che viene archiviato come BigIntegerda long intCompact. Se non ne hai bisogno BigIntegere il valore non scalato si inserisce in a, long BigDecimalsembra cercare di risparmiare spazio il più a lungo possibile.


Non ho idea di cosa tu abbia scritto (specialmente con l'ultima frase).
Buhake Sindi,

@The Elite Gentlement L'ultima frase dovrebbe solo dire che BigDecimalmantiene internamente il suo valore non scalato in a longe a BigInteger. Se BigIntegernon è necessario internamente, non viene creato ma se è necessario (ad es. Quando equalsincontra un gonfio e un gonfio non gonfiato BigDecimal) () `viene utilizzato per crearlo. - Per riassumere: inflate()gestisce le conversioni interne se necessario e poiché è privato, non dovrebbe importare agli utenti della classe.
Thomas,

1

Credo che la risposta corretta sarebbe fare in modo che i due numeri (BigDecimals) abbiano la stessa scala, quindi possiamo decidere della loro uguaglianza. Ad esempio, questi due numeri sono uguali?

1.00001 and 1.00002

Bene, dipende dalla scala. Sulla scala 5 (5 punti decimali), no, non sono gli stessi. ma su precisioni decimali più piccole (scala 4 e inferiore) sono considerate uguali. Quindi suggerisco di rendere uguale la scala dei due numeri e poi confrontarli.


-10

Puoi anche confrontare con il doppio valore

BigDecimal a= new BigDecimal("1.1"); BigDecimal b =new BigDecimal("1.1");
System.out.println(a.doubleValue()==b.doubleValue());

5
Si prega di evitare questa soluzione il più possibile. Anche i doppi dovrebbero essere confrontati con "epsilon". Non ha senso avere BigDecimal e confrontarlo come doppio ... c'è un'alta probabilità che ti spari una gamba.
Vadim Kirilchuk,

I valori doppi devono essere confrontati usando epsillons
Bishwajit Purkaystha
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.