Comparável e Comparator em Java são muito úteis para ordenar a coleção de objetos. Java fornece alguns métodos internos para ordenar array de tipos primitivos ou array de classes Wrapper ou lista. Aqui nós vamos primeiro aprender como podemos ordenar um array/lista de tipos primitivos e classes wrapper e então nós vamos usar as interfaces java.lang.Comparable e java.util.Comparator para ordenar array/lista de classes personalizadas. Vamos ver como podemos ordenar tipos primitivos ou array de objeto e lista 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 array de primitivos como array de inteiros
int[] intArr = {5,9,1,10};
Arrays.sort(intArr);
System.out.println(Arrays.toString(intArr));
//ordenar array 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 um array 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
//isto é substituído para imprimir a informação amigável 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 o array de objetos Funcionário.
//ordenar array de objeto
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 array 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, ocorre 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
Java fornece a 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), utilizado pelos métodos de ordenação; você pode verificar qualquer classe Wrapper, String ou Date para confirmar isso. Devemos substituir esse método de maneira que ele retorne um número inteiro negativo, zero ou um número inteiro positivo se o objeto “this” for menor, igual ou maior que o objeto passado como argumento. Após implementar a interface Comparable na classe Employee, aqui está o resultado da classe 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 ascendente
// retorna um número inteiro negativo, zero ou um número inteiro positivo como este id do funcionário
// é menor, igual ou maior que o objeto especificado.
return (this.id - emp.id);
}
@Override
// isso é necessário para imprimir informações amigáveis sobre o Employee
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]";
}
}
Agora, ao executarmos o trecho acima para a ordenação de Arrays de Employees e imprimirmos, 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 pelo id em ordem ascendente. Mas, na maioria dos cenários da vida real, queremos ordenar com base 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 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 forem iguais e um int positivo se o primeiro argumento for maior que o segundo. Comparable e Comparator interfaces 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 Funcionário.
/**
* 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.
//ordena o array de empregados por Salário
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
//ordena o array de empregados por Idade
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
//ordena o array de empregados 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 trecho 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]]
Então agora sabemos que se quisermos ordenar um array de objetos java ou lista, precisamos implementar a interface java Comparable para fornecer ordenação padrão e devemos implementar a interface java Comparator para fornecer diferentes maneiras de ordenar. 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 ascendente
//retorna um inteiro negativo, zero ou um inteiro positivo conforme este id de empregado
//é 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 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 de classe separada da interface Comparator que comparará dois objetos Empregados primeiro pelo id e se forem iguais, então pelo 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 maneiras 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) {
//classificação 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);
//classificar 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));
//classificar 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));
//classificar 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));
//classificar 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 classificados por ID e depois 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 a ordenação de objetos em java.
Comparable vs Comparator
- A interface Comparable pode ser usada para fornecer uma maneira única de ordenação, enquanto a interface Comparator é usada para fornecer diferentes maneiras de ordenação.
- Para usar Comparable, a classe precisa implementá-la, enquanto para usar Comparator não precisamos fazer nenhuma alteração na classe.
- A interface Comparable está no pacote
java.lang
, enquanto a interface Comparator está presente no pacotejava.util
. - Não precisamos fazer nenhuma alteração no 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ê conhece 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 core em nosso Repositório no GitHub.
Source:
https://www.digitalocean.com/community/tutorials/comparable-and-comparator-in-java-example