Comparable e Comparator in Java sono molto utili per ordinare la collezione di oggetti. Java fornisce alcuni metodi incorporati per ordinare array di tipi primitivi o array di classi Wrapper o liste. Qui impareremo prima come ordinare un array/lista di tipi primitivi e classi wrapper, e poi useremo le interfacce java.lang.Comparable e java.util.Comparator per ordinare array/lista di classi personalizzate. Vediamo come possiamo ordinare un array/lista di tipi primitivi o oggetti con un semplice programma.
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) {
//ordinamento di array di tipi primitivi come int array
int[] intArr = {5,9,1,10};
Arrays.sort(intArr);
System.out.println(Arrays.toString(intArr));
//ordinamento di array di stringhe
String[] strArr = {"A", "C", "B", "Z", "E"};
Arrays.sort(strArr);
System.out.println(Arrays.toString(strArr));
//ordinamento di una lista di oggetti di classi 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);
}
}
L’output del programma precedente è:
[1, 5, 9, 10]
[A, B, C, E, Z]
A B C E Z
Ora proviamo a ordinare un array di oggetti.
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
//questo metodo è sovrascritto per stampare informazioni leggibili sull'impiegato
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]";
}
}
Ecco il codice che ho usato per ordinare l’array di oggetti Employee.
//ordinamento di array di oggetti
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);
//ordinamento dell'array di impiegati utilizzando l'implementazione dell'interfaccia Comparable
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
Quando ho provato ad eseguirlo, viene generata l’eccezione di runtime seguente.
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 fornisce l’interfaccia Comparable che dovrebbe essere implementata da qualsiasi classe personalizzata se vogliamo utilizzare i metodi di ordinamento di Arrays o Collections. L’interfaccia Comparable ha il metodo compareTo(T obj) che è utilizzato dai metodi di ordinamento, è possibile verificare qualsiasi classe Wrapper, String o Date per confermare questo. Dovremmo sovrascrivere questo metodo in modo tale che restituisca un numero intero negativo, zero o positivo se l’oggetto “this” è minore, uguale o maggiore dell’oggetto passato come argomento. Dopo aver implementato l’interfaccia Comparable nella classe Employee, ecco la classe Employee risultante.
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) {
// ordiniamo gli impiegati in base a un id in ordine ascendente
// restituisce un numero intero negativo, zero o positivo come id di questo impiegato
// è minore di, uguale a o maggiore dell'oggetto specificato.
return (this.id - emp.id);
}
@Override
// ciò è necessario per stampare le informazioni user-friendly sull'Employee
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]";
}
}
Ora quando eseguiamo il frammento sopra per ordinare gli Array degli Employee e stamparlo, ecco l’output.
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]]
Come puoi vedere, l’array degli dipendenti è ordinato per ID in ordine crescente. Tuttavia, nella maggior parte degli scenari reali, desideriamo un ordinamento basato su diversi parametri. Ad esempio, come CEO, vorrei ordinare i dipendenti in base al salario, mentre un responsabile delle risorse umane vorrebbe ordinarli in base all’età. Questa è la situazione in cui è necessario utilizzare l’interfaccia Java Comparator perché l’implementazione del metodo Comparable.compareTo(Object o) può fornire un ordinamento predefinito e non possiamo cambiarlo dinamicamente. Con Comparator, possiamo definire più metodi con modi diversi di ordinamento e quindi scegliere il metodo di ordinamento in base alle nostre esigenze.
Java Comparator
L’interfaccia Comparator richiede l’implementazione del metodo compare(Object o1, Object o2), che prende due argomenti di tipo Object. Dovrebbe essere implementato in modo che restituisca un valore intero negativo se il primo argomento è minore del secondo, zero se sono uguali e un valore intero positivo se il primo argomento è maggiore del secondo. Le interfacce Comparable e Comparator utilizzano i generics per la verifica del tipo in fase di compilazione; per ulteriori informazioni, consulta Java Generics. Ecco come possiamo creare diverse implementazioni di Comparator nella 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());
}
};
Tutte le implementazioni sopra dell’interfaccia Comparator sono classi anonime. Possiamo utilizzare questi comparatori per passare un argomento alla funzione di ordinamento delle classi Arrays e Collections.
//ordina l'array degli impiegati utilizzando Comparator per Salario
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
//ordina l'array degli impiegati utilizzando Comparator per Età
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
//ordina l'array degli impiegati utilizzando Comparator per Nome
Arrays.sort(empArr, Employee.NameComparator);
System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));
Ecco l’output del frammento di codice sopra:
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]]
Ora sappiamo che se vogliamo ordinare un array di oggetti Java o una lista, dobbiamo implementare l’interfaccia Comparable di Java per fornire un ordinamento predefinito e dovremmo implementare l’interfaccia Comparator di Java per fornire modi diversi di ordinamento. Possiamo anche creare una classe separata che implementa l’interfaccia Comparator
e poi utilizzarla. Ecco le classi finali che spiegano Comparable e Comparator in 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) {
//ordiniamo l'impiegato in base a un id in ordine crescente
//restituisce un numero intero negativo, zero, o un numero intero positivo come questo id dell'impiegato
//è minore, uguale o maggiore dell'oggetto specificato.
return (this.id - emp.id);
}
@Override
//questo è richiesto per stampare le informazioni user-friendly sull'Impiegato
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());
}
};
}
Ecco l’implementazione della classe separata dell’interfaccia Comparator che comparerà due oggetti Impiegato prima sul loro id e se sono uguali, poi sul 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;
}
}
Ecco la classe di test dove stiamo utilizzando modi diversi per ordinare gli oggetti in Java utilizzando 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) {
//ordinamento array oggetti personalizzati
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);
//ordinamento array dipendenti usando l'implementazione dell'interfaccia Comparable
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
//ordina array dipendenti usando Comparator per lo stipendio
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
//ordina array dipendenti usando Comparator per l'età
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
//ordina array dipendenti usando Comparator per il nome
Arrays.sort(empArr, Employee.NameComparator);
System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));
//Elenco dipendenti ordinato per ID e poi nome usando la 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));
}
}
Ecco l’output del programma precedente:
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]]
Le interfacce java.lang.Comparable e java.util.Comparator sono potenti strumenti che possono essere utilizzati per ordinare gli oggetti in Java.
Comparable vs Comparator
- L’interfaccia Comparable può essere utilizzata per fornire un unico modo di ordinare, mentre l’interfaccia Comparator viene utilizzata per fornire modi diversi di ordinamento.
- Per utilizzare Comparable, la classe deve implementarla, mentre per utilizzare Comparator non è necessario apportare alcuna modifica alla classe.
- L’interfaccia Comparable si trova nel pacchetto
java.lang
, mentre l’interfaccia Comparator è presente nel pacchettojava.util
. - Non è necessario apportare alcuna modifica al codice lato client per utilizzare Comparable; i metodi
Arrays.sort()
oCollection.sort()
utilizzano automaticamente il metodocompareTo()
della classe. Per Comparator, il client deve fornire la classe Comparator da utilizzare nel metodo compare().
Lo sai che il metodo Collections.sort() che accetta un argomento Comparator segue il Pattern Strategia?
Puoi controllare il codice completo e altri esempi di core java dal nostro Repository GitHub.
Source:
https://www.digitalocean.com/community/tutorials/comparable-and-comparator-in-java-example