Comparable e Comparator em Java são muito úteis para ordenar a coleção de objetos. Java fornece alguns métodos integrados para ordenar matriz de tipos primitivos ou matriz de classes Wrapper ou lista. Aqui, vamos primeiro aprender como podemos ordenar uma matriz/lista de tipos primitivos e classes Wrapper e, em seguida, vamos usar as interfaces java.lang.Comparable e java.util.Comparator para ordenar uma matriz/lista de classes personalizadas. Vamos ver como podemos ordenar uma matriz/lista de tipos primitivos ou objetos com um programa simples.
package com.journaldev.sort;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class JavaObjectSorting {
/**
* This class shows how to sort primitive arrays,
* Wrapper classes Object Arrays
* @param args
*/
public static void main(String[] args) {
//ordenar matriz de tipos primitivos como matriz de inteiros
int[] intArr = {5,9,1,10};
Arrays.sort(intArr);
System.out.println(Arrays.toString(intArr));
//ordenar matriz de strings
String[] strArr = {"A", "C", "B", "Z", "E"};
Arrays.sort(strArr);
System.out.println(Arrays.toString(strArr));
//ordenar lista de objetos de classes Wrapper
List strList = new ArrayList();
strList.add("A");
strList.add("C");
strList.add("B");
strList.add("Z");
strList.add("E");
Collections.sort(strList);
for(String str: strList) System.out.print(" "+str);
}
}
A saída do programa acima é:
[1, 5, 9, 10]
[A, B, C, E, Z]
A B C E Z
Agora vamos tentar ordenar uma matriz de objetos.
package com.journaldev.sort;
public class Employee {
private int id;
private String name;
private int age;
private long salary;
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public long getSalary() {
return salary;
}
public Employee(int id, String name, int age, int salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
//isso é sobrescrito para imprimir informações amigáveis sobre o Funcionário
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]";
}
}
Aqui está o código que usei para ordenar a matriz de objetos Funcionário.
//ordenar matriz de objetos
Employee[] empArr = new Employee[4];
empArr[0] = new Employee(10, "Mikey", 25, 10000);
empArr[1] = new Employee(20, "Arun", 29, 20000);
empArr[2] = new Employee(5, "Lisa", 35, 5000);
empArr[3] = new Employee(1, "Pankaj", 32, 50000);
//ordenar matriz de funcionários usando a implementação da interface Comparable
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
Quando tentei executar isso, ele lançou a seguinte exceção em tempo de execução.
Exception in thread "main" java.lang.ClassCastException: com.journaldev.sort.Employee cannot be cast to java.lang.Comparable
at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:290)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:157)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
at java.util.Arrays.sort(Arrays.java:472)
at com.journaldev.sort.JavaSorting.main(JavaSorting.java:41)
Comparable e Comparator
O Java fornece uma interface Comparable que deve ser implementada por qualquer classe personalizada se quisermos usar os métodos de ordenação de Arrays ou Collections. A interface Comparable possui o método compareTo(T obj) que é utilizado pelos métodos de ordenação; você pode verificar qualquer classe Wrapper, String ou Date para confirmar isso. Devemos substituir este método de tal forma que ele retorne um número inteiro negativo, zero, ou um número inteiro positivo se o objeto “this” for menor que, igual a, ou maior que o objeto passado como argumento. Após implementar a interface Comparable na classe Employee, aqui está a classe resultante do Employee.
package com.journaldev.sort;
import java.util.Comparator;
public class Employee implements Comparable {
private int id;
private String name;
private int age;
private long salary;
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public long getSalary() {
return salary;
}
public Employee(int id, String name, int age, int salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public int compareTo(Employee emp) {
//vamos ordenar os funcionários com base em um id em ordem crescente
//retorna um número inteiro negativo, zero, ou um número inteiro positivo como este id de funcionário
//é menor que, igual a, ou maior que o objeto especificado.
return (this.id - emp.id);
}
@Override
//isso é necessário para imprimir as informações amigáveis ao usuário sobre o Employee
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]";
}
}
Agora, quando executamos o trecho acima para a ordenação de Arrays de Employees e imprimimos, aqui está a saída.
Default Sorting of Employees list:
[[id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000]]
Como você pode ver, a matriz de funcionários está ordenada por ID em ordem ascendente. No entanto, na maioria dos cenários da vida real, queremos ordenação baseada em diferentes parâmetros. Por exemplo, como CEO, gostaria de ordenar os funcionários com base no salário, um RH gostaria de ordená-los com base na idade. Esta é a situação em que precisamos usar a interface Java Comparator porque a implementação do método Comparable.compareTo(Object o) pode fornecer uma ordenação padrão e não podemos alterá-la dinamicamente. Enquanto isso, com Comparator, podemos definir vários métodos com diferentes formas de ordenação e depois escolher o método de ordenação com base em nossos requisitos.
Java Comparator
A interface Comparator compare(Object o1, Object o2) precisa ser implementada, que recebe dois argumentos de objeto, ela deve ser implementada de tal forma que retorne um int negativo se o primeiro argumento for menor que o segundo e retorne zero se eles forem iguais e um int positivo se o primeiro argumento for maior que o segundo. As interfaces Comparable e Comparator usam Genéricos para verificação de tipo em tempo de compilação, saiba mais sobre Java Generics. Aqui está como podemos criar diferentes implementações de Comparator na classe Employee.
/**
* Comparator to sort employees list or array in order of Salary
*/
public static Comparator<Employee> SalaryComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return (int) (e1.getSalary() - e2.getSalary());
}
};
/**
* Comparator to sort employees list or array in order of Age
*/
public static Comparator<Employee> AgeComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getAge() - e2.getAge();
}
};
/**
* Comparator to sort employees list or array in order of Name
*/
public static Comparator<Employee> NameComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getName().compareTo(e2.getName());
}
};
Todas as implementações acima da interface Comparator são classes anônimas. Podemos usar esses comparadores para passar um argumento para a função de ordenação das classes Arrays e Collections.
//ordenar a array de empregados usando Comparator por Salário
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
//ordenar a array de empregados usando Comparator por Idade
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
//ordenar a array de empregados usando Comparator por Nome
Arrays.sort(empArr, Employee.NameComparator);
System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));
Aqui está a saída do snippet de código acima:
Employees list sorted by Salary:
[[id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000]]
Employees list sorted by Age:
[[id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000]]
Employees list sorted by Name:
[[id=20, name=Arun, age=29, salary=20000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=1, name=Pankaj, age=32, salary=50000]]
Agora sabemos que se quisermos ordenar arrays de objetos java ou listas, precisamos implementar a interface Comparable java para fornecer ordenação padrão e devemos implementar a interface Comparator java para fornecer diferentes formas de ordenação. Também podemos criar uma classe separada que implementa a interface Comparator
e então usá-la. Aqui estão as classes finais que temos explicando Comparable e Comparator em Java.
package com.journaldev.sort;
import java.util.Comparator;
public class Employee implements Comparable {
private int id;
private String name;
private int age;
private long salary;
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public long getSalary() {
return salary;
}
public Employee(int id, String name, int age, int salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public int compareTo(Employee emp) {
//vamos ordenar o empregado baseado em um id em ordem crescente
//retorna um número inteiro negativo, zero, ou um número inteiro positivo como este id de empregado
//é menor, igual, ou maior que o objeto especificado.
return (this.id - emp.id);
}
@Override
//isto é necessário para imprimir as informações amigáveis sobre o Empregado
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]";
}
/**
* Comparator to sort employees list or array in order of Salary
*/
public static Comparator SalaryComparator = new Comparator() {
@Override
public int compare(Employee e1, Employee e2) {
return (int) (e1.getSalary() - e2.getSalary());
}
};
/**
* Comparator to sort employees list or array in order of Age
*/
public static Comparator AgeComparator = new Comparator() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getAge() - e2.getAge();
}
};
/**
* Comparator to sort employees list or array in order of Name
*/
public static Comparator NameComparator = new Comparator() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getName().compareTo(e2.getName());
}
};
}
Aqui está a implementação da classe separada da interface Comparator que irá comparar dois objetos de Empregados primeiro em sua id e se forem os mesmos, então no nome.
package com.journaldev.sort;
import java.util.Comparator;
public class EmployeeComparatorByIdAndName implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
int flag = o1.getId() - o2.getId();
if(flag==0) flag = o1.getName().compareTo(o2.getName());
return flag;
}
}
Aqui está a classe de teste onde estamos usando diferentes formas de ordenar Objetos em java usando Comparable e Comparator.
package com.journaldev.sort;
import java.util.Arrays;
public class JavaObjectSorting {
/**
* This class shows how to sort custom objects array/list
* implementing Comparable and Comparator interfaces
* @param args
*/
public static void main(String[] args) {
//ordenando array de objetos personalizados
Employee[] empArr = new Employee[4];
empArr[0] = new Employee(10, "Mikey", 25, 10000);
empArr[1] = new Employee(20, "Arun", 29, 20000);
empArr[2] = new Employee(5, "Lisa", 35, 5000);
empArr[3] = new Employee(1, "Pankaj", 32, 50000);
//ordenando array de funcionários usando implementação da interface Comparable
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
//ordenar array de funcionários usando Comparator por Salário
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
//ordenar array de funcionários usando Comparator por Idade
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
//ordenar array de funcionários usando Comparator por Nome
Arrays.sort(empArr, Employee.NameComparator);
System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));
//Lista de funcionários ordenada por ID e depois por nome usando a classe Comparator
empArr[0] = new Employee(1, "Mikey", 25, 10000);
Arrays.sort(empArr, new EmployeeComparatorByIdAndName());
System.out.println("Employees list sorted by ID and Name:\n"+Arrays.toString(empArr));
}
}
Aqui está a saída do programa acima:
Default Sorting of Employees list:
[[id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000]]
Employees list sorted by Salary:
[[id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000]]
Employees list sorted by Age:
[[id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000]]
Employees list sorted by Name:
[[id=20, name=Arun, age=29, salary=20000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=1, name=Pankaj, age=32, salary=50000]]
Employees list sorted by ID and Name:
[[id=1, name=Mikey, age=25, salary=10000], [id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000]]
As interfaces java.lang.Comparable e java.util.Comparator são poderosas e podem ser usadas para fornecer ordenação de objetos em java.
Comparable vs Comparator
- A interface Comparable pode ser usada para fornecer uma única forma de ordenação, enquanto a interface Comparator é usada para fornecer diferentes formas de ordenação.
- Para usar Comparable, a Classe precisa implementá-la, enquanto para usar Comparator não precisamos fazer nenhuma mudança na classe.
- A interface Comparable está no pacote
java.lang
, enquanto a interface Comparator está presente no pacotejava.util
. - Não precisamos fazer nenhuma mudança de código no lado do cliente para usar Comparable, os métodos
Arrays.sort()
ouCollection.sort()
usam automaticamente o métodocompareTo()
da classe. Para Comparator, o cliente precisa fornecer a classe Comparator a ser usada no método compare().
Você sabe que o método Collections.sort() que recebe um argumento Comparator segue o Padrão de Estratégia?
Você pode conferir o código completo e mais exemplos de Java básico em nosso Repositório no GitHub.
Source:
https://www.digitalocean.com/community/tutorials/comparable-and-comparator-in-java-example