BigDecimal é igual a () versus compareTo ()

157

Considere a classe de teste simples:

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");
    }

}

Você pode (conscientemente) dizer que xé igual a y(não referência a objeto), mas quando você executa o programa, o seguinte resultado mostra:

false
true

Pergunta: Qual é a diferença entre compareTo()e equals()em BigDecimalque compareTopode determinar que xé igual a y?

PS: Vejo que o BigDecimal tem um inflate()método no equals()método O que inflate()faz realmente?

Buhake Sindi
fonte
1
Anúncio inflate(): não faz parte da API pública porque manipula apenas a representação interna e não tem efeito visível para o "exterior". Portanto, a menos que você queira realmente estudar a implementação BigDecimalem profundidade, sugiro que você ignore esse método.
Joachim Sauer
Uma breve explicação e fonte trechos de código podem ser encontrados aqui
xenteros

Respostas:

224

A resposta está no JavaDoc do equals()método :

Diferentemente compareTo, esse método considera dois BigDecimalobjetos iguais apenas se forem iguais em valor e escala (portanto, 2,0 não é igual a 2,00 quando comparado por este método).

Em outras palavras: equals()verifica se os BigDecimalobjetos são exatamente iguais em todos os aspectos. compareTo()"only" compara seu valor numérico.

Quanto ao porquê equals() se comportar dessa maneira, isso foi respondido nesta pergunta do SO .

Joachim Sauer
fonte
24
Essa é uma parte muito complicada, BigDecimalse você não ler o JavaDoc com atenção. :) - Temos alguns erros estranhos até percebermos a diferença.
Thomas
3
Muitas partes da API padrão agem "de maneira não intuitiva", quando a coisa intuitiva não está correta. BigDecimalé uma dessas coisas. Portanto, deve-se sempre verificar o JavaDoc. Pelo menos uma vez que você descobrir algo estranho está acontecendo.
Joachim Sauer
7
Engraçado. Depois de ler a sua resposta Acabei de verificar Comparável e afirma que consistência com iguais "é altamente recomendável (mas não obrigatório)"
SJuan76
4
Eu perguntei por que: stackoverflow.com/questions/14102083/…
bacar
8
@ StephenPH Eu acho incorreto que essa inconsistência exista.
Matt R
1

Vejo que BigDecimal tem um método inflate () no método equals (). O que inflate () realmente faz?

Basicamente, inflate()chama , BigInteger.valueOf(intCompact)se necessário, ou seja, cria o valor não escalado que é armazenado como um BigIntegerde long intCompact. Se você não precisar disso BigIntegere o valor não dimensionado se encaixar em um, long BigDecimalparece tentar economizar espaço o máximo de tempo possível.

Thomas
fonte
Não tenho ideia do que você escreveu (especialmente com a última frase).
Buhake Sindi
@ The Elite Gentlement A última frase deve dizer apenas que internamente BigDecimalmantém seu valor não dimensionado em um longe em outro BigInteger. Se BigIntegernão for necessário internamente, ele não será criado, mas será necessário (por exemplo, quando equalsencontrar um inflado inflado e não inflado BigDecimal) () `é usado para criá-lo. - Para resumir: inflate()trata de conversões internas, se necessário e é privado, isso não deve importar para os usuários da classe #
Thomas
1

Acredito que a resposta correta seria fazer com que os dois números (BigDecimals) tenham a mesma escala, para que possamos decidir sobre sua igualdade. Por exemplo, esses dois números são iguais?

1.00001 and 1.00002

Bem, isso depende da escala. Na escala 5 (5 casas decimais), não, eles não são os mesmos. mas em precisões decimais menores (escala 4 e inferior) são consideradas iguais. Então, sugiro que a escala dos dois números seja igual e depois compare-os.

Mr.Q
fonte
-10

Você também pode comparar com valor duplo

BigDecimal a= new BigDecimal("1.1"); BigDecimal b =new BigDecimal("1.1");
System.out.println(a.doubleValue()==b.doubleValue());
Rashmi singh
fonte
5
Por favor, evite esta solução, tanto quanto possível. Mesmo duplos devem ser comparados com "epsilon". Não faz sentido ter o BigDecimal e compará-lo como dobra .. há uma probabilidade muito alta de que você atire na sua própria perna.
Vadim Kirilchuk
Valores Douuble deve ser comparada usando epsillons
Bishwajit Purkaystha