Comparando Números em Java

Em Java, todos os tipos numéricos se estendem de java.lang.Number. Seria uma boa ideia ter um método como o seguinte:

public boolean areEqual(Number first, Number second) { if (first != null && second != null) { return first.equals(second); } } 

Estou preocupado com casos em que um duplo 2,00000 não é igual a um int 2. Eles são manipulados pelos iguais integrados? Se não, existe alguma maneira de escrever uma function simples de comparação de números em java? (bibliotecas externas como o apache commons são ok)

Um Double NUNCA é equals a um Integer . Além disso, um double não é o mesmo que um Double .

Java tem tipos primitivos e tipos de referência. Os tipos verdadeiramente numéricos em Java não se estendem de Number , porque são primitivos.

Você pode querer considerar um sistema em que você não esteja misturando tipos, porque isso geralmente causará muitos problemas com conversões implícitas / explícitas que podem / não perder informações, etc.

Perguntas relacionadas

Em int vs Integer :

  • Qual é a diferença entre um int e um Integer em Java / C #?
  • Java é totalmente orientado a objects?

Comparação de Number :

  • Por que o java.lang.Number não java.lang.Number Comparable ?
  • Comparando os valores de dois números genéricos

Veja também

  • Guia de Linguagem Java / Autoboxing
  • JLS 4.2 4.2 Tipos e valores primitivos

    Os tipos numéricos são os tipos integrais e os tipos de ponto flutuante. Os tipos integrais são byte , short , int e long e char . Os tipos de ponto float são float e double .


Em computação de tipo misto

Computação de tipo misto é o assunto de pelo menos 4 quebra-cabeças em Java Puzzlers .

Aqui estão vários trechos:

geralmente é melhor evitar cálculos do tipo misto porque eles […] são intrinsecamente confusos. […] Em nenhum lugar isso é mais aparente do que em expressões condicionais. Comparações de tipo misto são sempre confusas porque o sistema é forçado a promover um operando para corresponder ao tipo de outro. A conversão é invisível e pode não produzir os resultados esperados

Prescrição : Evite cálculos que misturem tipos integrais e de ponto flutuante. Prefira aritmética integral para ponto flutuante.

Eu sei que é um tópico antigo, mas …. Para comparar dois números em Java, você pode usar o método compareTo do BigDecimal. O BigDecimal pode armazenar tudo desde curto até o dobro ou BigInteger, então é a class perfeita para isso.

Então você pode tentar escrever algo assim:

 public int compareTo(Number n1, Number n2) { // ignoring null handling BigDecimal b1 = new BigDecimal(n1.doubleValue()); BigDecimal b2 = new BigDecimal(n2.doubleValue()); return b1.compareTo(b2); } 

Essa certamente não é a melhor abordagem em relação ao desempenho. Os testes seguintes funcionaram até agora, pelo menos com o JDK7:

 assertTrue(compareTo(new Integer(1), new Integer(2)) == -1); assertTrue(compareTo(new Integer(1), new Double(2.0)) == -1); assertTrue(compareTo(new Integer(1), new Double(Double.MAX_VALUE)) == -1); assertTrue(compareTo(new Integer(1), new Double(Double.MIN_VALUE)) == 1); assertTrue(compareTo(new Integer(1), new Double(1.000001)) == -1); assertTrue(compareTo(new Integer(1), new Double(1.000)) == 0); assertTrue(compareTo(new Integer(1), new Double(0.25*4)) == 0); assertTrue(compareTo(new Integer(1), new AtomicLong(1)) == 0); 

O método específico que você sugere falha, porque está usando equals() herdado de Object . Ou seja, ele verificaria se os objects Number eram os mesmos e não se os valores eram os mesmos.

Se isso foi apenas um exemplo ilustrativo, atualizarei minha resposta.

A resposta do poligênio na verdade praticamente cobre o terreno para o qual eu estava indo. Você pode também estar interessado nesta questão: Por que o java.lang.Number não implementa o Comparable? .

Se você quiser saber se as referências de objects são iguais, os methods existentes se ajustam à conta. Um Double representando 2.0 e um Integer representando 2 são objects definitivamente diferentes, e certamente não são intercambiáveis ​​em um sentido geral.

Se você quer apenas saber se os valores numéricos são os mesmos, você pode usar o método Number.doubleValue () para converter ambos os números em duplas e comparar esses números juntos (provavelmente permitindo uma pequena tolerância, pois a maioria dos números é representada inexatamente , como 1.99999999996583 para o que deveria ser 2, dependendo das etapas de cálculo intermediárias). Algo como o seguinte:

 private static final double EPSILON = 0.000000000000001d; public static boolean areEquivalentNumbers(Number a, Number b) { if (a == null) { return b == null; } else if (b == null) { return false; } else { return Math.abs(a.doubleValue() - b.doubleValue()) < EPSILON; } } 

Comparar números entre inteiros e pontos flutuantes quase nunca renderá o que você procura. Se, no entanto, este for um exercício simples, você poderá implementar a comparação comparando as representações de string dos valores, como em:

 public boolean areEqual(Number first, Number second) { if (first == null) { return second == null; } if (second == null) { return false; } return first.toString().equals(second.toString()); } 

Na tangente de algumas respostas, sugiro que, em vez de escrever algo como:

 boolean compare(Object o1, Object o2) { if (o1==null) return o2==null; if (o2==null) return false; return o1.equals(o2); } 

É muito mais conciso, e acredito que seja um pouco mais eficiente, escrever:

 boolean compare(Object o1, Object o2) { return o1==o2 || o1!=null && o2!=null && o1.equals(o2); } 

Se ambos forem nulos, o1 == o2 retornará verdadeiro. Se eles não são, mas eles são o mesmo object, tudo bem também.

Tecnicamente o o2! = Null não é necessário para a maioria das implementações de iguais, mas se você estivesse realmente sendo tão genérico para fazer isso em Objetos como no exemplo acima, você obviamente não saberia como cada override foi escrito.

você não pode ligar

 number.equals(number2); 

porque, se number for um Double e number2 for Integer, eles não serão da mesma class e você receberá uma exceção informando o fato.

Você poderia escrever uma class de comparação que aceita objects Number, mas você terá que levar em conta as diferentes subclasss de Number