Comparador e Comparável em Java

Comparador e Comparável em Java

1. Introdução

Comparações em Java são muito fáceis - até que não sejam.

Ao trabalhar com tipos personalizados ou tentar comparar objetos que não são diretamente comparáveis, precisamos fazer uso de uma estratégia de comparação. Podemos construir um de forma simples, mas usando as interfacesComparator ouComparable.

2. Configurando o exemplo

Vejamos um exemplo de um time de futebol - onde queremos alinhar os jogadores por suas classificações.

Começaremos criando uma classePlayer simples:

public class Player {
    private int ranking;
    private String name;
    private int age;

    // constructor, getters, setters
}

A seguir, vamos criar uma classePlayerSorter para criar nossa coleção e tentar classificá-la usandoCollections.sort:

public static void main(String[] args) {
    List footballTeam = new ArrayList<>();
    Player player1 = new Player(59, "John", 20);
    Player player2 = new Player(67, "Roger", 22);
    Player player3 = new Player(45, "Steven", 24);
    footballTeam.add(player1);
    footballTeam.add(player2);
    footballTeam.add(player3);

    System.out.println("Before Sorting : " + footballTeam);
    Collections.sort(footballTeam);
    System.out.println("After Sorting : " + footballTeam);
}

Aqui, como esperado, isso resulta em um erro em tempo de compilação:

The method sort(List) in the type Collections
  is not applicable for the arguments (ArrayList)

Vamos entender o que fizemos de errado aqui.

3. Comparable

Como o nome sugere,Comparable is an interface defining a strategy of comparing an object with other objects of the same type. This is called the class’s “natural ordering”.

Assim, para podermos classificar - devemos definir nosso objetoPlayer como comparável implementando a interfaceComparable:

public class Player implements Comparable {

    //...
    @Override
    public int compareTo(Player otherPlayer) {
        return (this.getRanking() - otherPlayer.getRanking());
    }
}

A ordem de classificação é decidida pelo valor de retorno decompareTo() método.

O método retorna um número indicando se o objeto que está sendo comparado é menor que, igual ou maior que o objeto que está sendo passado como argumento.

Finalmente, quando executamos nossoPlayerSorter agora, podemos ver nossosPlayers classificados por sua classificação:

Before Sorting : [John, Roger, Steven]
After Sorting : [Steven, John, Roger]

Agora que temos uma compreensão clara da ordem natural comComparable, vamos verhow we can use other types of ordering, in a more flexible manner além de implementar diretamente uma interface.

4. Comparator

The Comparator interface defines a compare(arg1, arg2) method com dois argumentos que representam objetos comparados e funcionam de maneira semelhante ao métodoComparable.compareTo().

4.1. CriandoComparators

Para criar umComparator,, temos que implementar a interfaceComparator.

Em nosso primeiro exemplo, criaremos umComparator para usar o atributoranking dePlayer para classificar os jogadores:

public class PlayerRankingComparator implements Comparator {

    @Override
    public int compare(Player firstPlayer, Player secondPlayer) {
       return (firstPlayer.getRanking() - secondPlayer.getRanking());
    }
}

Da mesma forma, podemos criar umComparator para usar o atributoage dePlayer para classificar os jogadores:

public class PlayerAgeComparator implements Comparator {
    @Override
    public int compare(Player firstPlayer, Player secondPlayer) {
       return (firstPlayer.getAge() - secondPlayer.getAge());
    }
}

4.2. Comparators em ação

Para demonstrar o conceito, vamos modificar nossoPlayerSorter, introduzindo um segundo argumento paraCollections.sort method, que é realmente a instância deComparator que queremos usar.

Using this approach, we can override the natural ordering:

PlayerRankingComparator playerComparator = new PlayerRankingComparator();
Collections.sort(footballTeam, playerComparator);

Agora, vamos executar nossoPlayerRankingSorter to para ver o resultado:

Before Sorting : [John, Roger, Steven]
After Sorting by ranking : [Steven, John, Roger]

Se quisermos uma ordem de classificação diferente, precisamos apenas alterar osComparator que estamos usando:

PlayerAgeComparator playerComparator = new PlayerAgeComparator();
Collections.sort(footballTeam, playerComparator);

Agora, quando executamos nossoPlayerAgeSorter, podemos ver uma ordem de classificação diferente porage:

Before Sorting : [John, Roger, Steven]
After Sorting by age : [Roger, John, Steven]

4.3. Java 8Comparators

Java 8 fornece novas maneiras de definirComparators usando expressões lambda e o método de fábrica estáticocomparing().

Vejamos um exemplo rápido de como usar uma expressão lambda para criar umComparator:

Comparator byRanking
 = (Player player1, Player player2) -> player1.getRanking() - player2.getRanking();

O métodoComparator.comparing usa um método de cálculo da propriedade que será usada para comparar itens e retorna uma instânciaComparator correspondente:

Comparator byRanking = Comparator
  .comparing(Player::getRanking);
Comparator byAge = Comparator
  .comparing(Player::getAge);

Você pode explorar a funcionalidade do Java 8 em detalhes em nosso guiaJava 8 Comparator.comparing.

5. Comparator VsComparable

The Comparable interface is a good choice when used for defining the default ordering ou, em outras palavras, se é a principal forma de comparação de objetos.

Então, devemos nos perguntar por que usar aComparator se já temosComparable?

Existem várias razões pelas quais:

  • Às vezes, não podemos modificar o código-fonte da classe cujos objetos queremos classificar, tornando impossível o uso deComparable

  • UsarComparators nos permite evitar a adição de código adicional às nossas classes de domínio

  • Podemos definir várias estratégias de comparação diferentes, o que não é possível ao usarComparable

6. Conclusão

Neste tutorial, exploramos as interfacesComparableeComparator e discutimos as diferenças entre elas.

Para entender tópicos mais avançados de classificação, verifique nossos outros artigos, comoJava 8 Comparator,Java 8 Comparison with Lambdas.

E, como de costume, o código-fonte pode ser encontradoover on Github.