Igualdade em Java

Este texto foi atualizado e doado ao projeto Code Design World.

Comparações em Java

Para quem já usou uma linguagem de programação antes do Java, quando começa a usar Java tem uma certa dificuldade em fazer comparações de objetos. Principalmente testar a igualdade.

Java é fortemente orientado a objetos e isso tem profundas implicações. Uma delas passa pela diferenciação entre variável primitiva e variável de referência. Basicamente, uma variável primitiva expressa o próprio valor da variável enquanto uma variável de referencia é apenas um apontador para um objeto. Como existem variáveis de referencia para objetos e os objetos em si, a linguagem tem que oferecer formas de testar a igualdade das váriaveis, por um lado, e dos objetos, por outro. O teste de igualdade de variáveis é feito pelo operador == que compara o valor da variável. O teste de igualdade de objetos é feito pelo uso do método equals() presente em todos os objetos.

01
02 Integer a = new Integer ( 1 ) ;
03 Integer b = new Integer ( 1 ) ;
04
05 // a referencia ao objeto é diferente
06 assertFalse ( a==b ) ;
07
08 // mas o valor é o mesmo
09 assertTrue ( a.equals ( b )) ;
10

Código 1:

O facto de equals() ser um método presente em qualquer objeto permite que a lógica que compara o objeto seja modificada conforme o tipo de objeto. Este facto é importantissimo porque podemos ter controlo sobre o tipo de comparação que estamos fazendo mesmo quando o objeto não foi codificado por nós. Esta forma de comparação de objetos é principalmente importante quando agrupamos os objetos em coleções.

O método equals() presente em todos os objetos faz as vezes do operador de comparação de valor presente em outras linguagens (= ou ==, por exemplo). Contudo, testar a igualdade não é a única comparação que queremos fazer entre objetos.

Ordem: Maiores e Menores

Alguns objetos têm uma ordem intrínseca para os seus valores. O exemplo clássico são os objetos que representam números, mas também datas e sequencias de caracteres têm uma ordem intrínseca.
Para este tipos de objetos é comum termos que saber se um certo objeto tem valor menor ou maior que outro Existem duas formas em Java de comparar a ordem dos objetos: implementar Comparable ou implementar Comparator

Implementar Comparator

Em outras linguagens e em java quando trabalhamos com tipos primitivos podemos usar operador de comparação de ordem como > e < ou mesmo >= e <=.

1
2 int a = 2 ;
3 int b = 3 ;
4
5 assertTrue ( a<=b ) ;
6

Código 2:

Podemos pensar em outra forma de comparar os valores de a e b usando a operação de subtração.

1
2 int a = 2 ;
3 int b = 3 ;
4
5 assertTrue ( a-b<= 0 ) ;
6

Código 3:

Uma simples alteração matemática da forma de comparar e passámos a comparar um numero com zero. Agora basta aplica o principio de separação de responsabilidade e encapsular a operação num método

1
2 int a = 2 ;
3 int b = 3 ;
4
5 assertTrue ( compare ( a,b ) <= 0 ) ;
6

Código 4:

Poderiamos agora trocar a definição de a e b para objetos que a nossa forma de comparação não se altera.

1
2 Integer a = new Integer ( 2 ) ;
3 Integer b = new Integer ( 2 ) ;
4
5 assertTrue ( compare ( a,b ) <= 0 ) ;
6

Código 5:

Basta agora padronizar o uso daquele método criando uma interface, que qualquer objeto pode implementar e onde esconder a real comparação dos objetos. Essa interface é: Comparator

1
2 public interface Comparator<T> {
3
4 public int compare ( T a, T b ) ;
5
6 }
7

Código 6:

Comparator permite construir qualquer forma de comparação de dois objetos. É especialmente indicado quando o objeto não tem uma ordem intrínseca ou tem mais do que uma ordem possível. Por exemplo: Produto pode ser ordenado por nome, for fabricante ou por preço.

A implementação de compare() é baseada no conceito de que estamos subtraindo os valores dos objetos como se eles fossem numeros. Então, se os objetos representam o mesmo valor, o resultado será zero. Se o valor representado por a for maior que o de b o resultado é um numero maior que zero. Qualquer número, maior que zero, pode ser retornado. Se o valor representado por a for menor que o de b o resultado é um numero menor que zero. Qualquer número, menor que zero, pode ser retornado.

Com estas regras simples, é possivel implementar comparação para qualquer tipo de objeto. Afinal matemática é muito mais que fazer contas…

Implementar Comparable

Algums objetos, como aqueles que representam numeros e datas, por exemplo, têm uma ordem intrinseca – chamada de ordem natural. Para os objetos que têm uma ordem natural o objeto, ele próprio, deve implementar a interface Comparable. A implementação do único método de Comparable, compareTo() segue as mesmas regras que o método em Comparator com a vantagem de não obrigar a instanciar um objeto especial para fazer a comparação.

compareTo() vs. equals()

Ao implementar Comparable temos agora duas formas de saber se dois objetos são iguais:

1
2
3 // podemos usar equals()
4 assertTrue ( a.equals ( b )) ;
5
6 // ou usar compareTO()
7 assertTrue ( a.compareTo ( b ) == 0 ) ;
8

Código 7:

Será que podemos usar qualquer um dos métodos indescriminadamente ? Não. Estes dois métodos só são equivalentes se a implementação de compareTo() for compativel com equals(). Ou seja, se quando os objetos são iguais, a diferença entre eles é zero. É necessário consultar a documentação da implementação do objeto para saber se a implementação é,ou não, compativel. Quando o uso é equivalente diz-se que “a implementação de Comparable é compatível com equals”.

Um exemplo de objeto cujo método Compare() pode não ser compativel com equals() é Money . O objecto Money contém um valor numérico e uma moeda. Dois valores de money são iguais apenas quando o valor numérico e a moeda forem iguais. Contudo, os valores de money podem ser considerados maiores ou menores apenas com base no valor numérico.

Nota: Esta implementação de Money, embora possivel e um exemplo de um objeto comparável não compativel com equals , não é uma implementação desejável. Objetos Money de moedas diferentes não devem sequer ser comparáveis. Uma leitura do Javadoc de Comparable é aconcelhavel

Conclusão

Em Java, o operador == testa a igualdade do valor da variável e não o valor do conteúdo da variável. A diferença só é relevante quando a variável é uma referência a um objeto.

Para descobrir se dois objetos são iguais temos que usar o método equals() presente em todo e qualquer objeto Java.

Vários tipos de objeto são ordenáveis. Ou seja, é possivel dizer que um objeto é maior, ou menor que outro. Alguns objetos têm uma única, e intrinseca, ordem possivel – a ordem natural ( ex.: Integer, String , Date , Money). Alguns objetos têm várias ordens possiveis ( ex.: Cliente, Produto )

Classes de objetos com ordem intrinseca devem implementar Comparable. Classes de objetos com várias ordens não devem implementar Comparable. Uma, ou mais, implementações de Comparator devem ser disponibilizadas à parte.

Comparator pode ser implementado para comparar qualquer tipo de objeto e vários podem ser implementados para comparar o mesmo tipo de objeto de formas diferentes. O método compare() substitui, para qualquer tipo de objeto, o uso dos operadores de comparação de tipos primitivos.

Comparable deve ser implementado apenas por objetos que têm uma ordem natural. Uma ordem instriseca.

Licença

Creative Commons License
Sérgio Taborda

Este trabalho é licenciado sob a Licença Creative Commons Atribuição-Uso Não-Comercial-Não a obras derivadas 3.0 Genérica .

2 opiniões sobre “Igualdade em Java”

  1. Era só para agradecer e felicitá-lo, porque a sua explicação sobre a Interface Comparable e Comparator foi bastante clara, objectiva e ajudou-me bastante a clarificar conceitos.
    Obrigado

  2. Bom artigo. Sobre igualdade, e as dificuldades de implementá-la corretamente, a Artima tem um artigo excelente: http://www.artima.com/lejava/articles/equality.html

    Na verdade, a dificuldade de implementar equals e hashcode corretamente não se aplica apenas à java: se aplica à todas linguagens orientdas a objetos, ou à linguagens funcionais onde se deseje implementar funções equivalente em para alguma estrutura de dados.

Deixe um comentário