Construcción de Comparable a partir de Comparator
En este ejemplo queremos ordenar instancias de la clase Person, para ello podemos utilizar la interfaz Comparator. Esta interfaz permite definir reglas personalizadas para la comparación de objetos con su método compare()lo que es indispensable cuando necesitamos múltiples criterios de ordenación.
La clase Person que representa a una persona, tiene 3 atributos: name que referencia al nombre de la persona, surname que referencia al apellido y age que referencia la edad. Estos tres atributos recibirán un valor a la hora de crear una instancia de la clase en el método main() de la clase con el mismo nombre.
En la clase Main, a parte de crearse instancias de la clase Person, se crea una instancia de la interfaz Comparator por cada atributo de la clase Person. Comparator tomará como tipo la clase Person debido a que el método compareTo() de dicha interfaz necesita recibir como argumento un par de objetos genéricos.
El primer Comparator, cuyo nombre es byName, lo que hace es comparar el nombre de las dos personas a comparar.
El segundo Comparator, cuyo nombre es bySurnameAndName, lo que hace es comparar el apellido de las dos personas a comparar. Si este es igual, compara respecto al nombre.
El tercer Comparator, cuyo nombre es byAgeAndSurnameAndName, lo que hace es comparar la edad de las dos personas a comparar. Si esta es igual, compara respecto al apellido y, si este también es igual, compara respecto al nombre.
import java.util.*;
class Person {
String name;
String surname;
int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public Integer getAge() {
return this.age;
}
}
public class Main {
public static void main(String[] args) {
Comparator<Person> byName = new Comparator<>(){
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
};
Comparator<Person> bySurnameAndName = new Comparator<>(){
public int compare(Person p1, Person p2) {
int alfa = p1.getSurname().compareTo(p2.getSurname());
if (alfa != 0) {
return alfa;
}
else {
return p1.getName().compareTo(p2.getName());
}
}
};
Comparator<Person> byAgeAndSurnameAndName = new Comparator<>>(){
public int compare(Person p1, Person p2) {
int alfa = p1.getAge().compareTo(p2.getAge());
if (alfa != 0) {
return alfa;
}
else {
int beta = p1.getSurname().compareTo(p2.getSurname());
if (beta != 0) {
return beta;
}
else {
return p1.getName().compareTo(p2.getName());
}
}
}
};
Person p1 = new Person("Paco", "Lopez", 10);
Person p2 = new Person("Paco", "Lopez", 15);
Person p3 = new Person("Juan", "Perez", 40);
System.out.println(byName.compare(p1, p2));
System.out.println(bySurnameAndName.compare(p1, p2));
System.out.println(byAgeAndSurnameAndName.compare(p1, p2));
}
}
De este ejemplo en adelante, lo que se busca es simpliciar los constructores de los Comparator hasta que el código quede lo más limpio y legible posible.
En este caso, no inicializamos directamente la instancia de los Comparator con un constructor, sino que vamos a definir directamente los parámetros de entrada de la lambda, de los cuales se va a usar el atributo name para comparar ambas instancias recibidas como argumento. En el bySurnameAndName y byAgeAndSurnameAndName se sigue la misma condición que el ejmplo anterior.
import java.util.*;
class Person {
String name;
String surname;
int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public Integer getAge() {
return this.age;
}
}
public class Main {
public static void main(String[] args) {
Comparator<Person> byName = (Person p1, Person p2) -> p1.getName().compareTo(p2.getName());
Comparator<Person> bySurnameAndName = (Person p1, Person p2) -> {
int alfa = p1.getSurname().compareTo(p2.getSurname());
if (alfa != 0) {
return alfa;
}
else {
return p1.getName().compareTo(p2.getName());
}
};
Comparator<Person> byAgeAndSurnameAndName = (Person p1, Person p2) -> {
int alfa = p1.getAge().compareTo(p2.getAge());
if (alfa != 0) {
return alfa;
}
else {
int beta = p1.getSurname().compareTo(p2.getSurname());
if (beta != 0) {
return beta;
}
else {
return p1.getName().compareTo(p2.getName());
}
}
};
Person p1 = new Person("Paco", "Lopez", 10);
Person p2 = new Person("Paco", "Lopez", 15);
Person p3 = new Person("Juan", "Perez", 40);
System.out.println(byName.compare(p1, p2));
System.out.println(bySurnameAndName.compare(p1, p2));
System.out.println(byAgeAndSurnameAndName.compare(p1, p2));
}
}
En este caso lo que hacemos es utilizar el método comparing() de Comparator en la variable byAge, al cual le pasamos como argumento una lambda que obtiene como resultado la edad de la persona pasada como parámetro de la lambda. Luego se utiliza el método thenComparing() del Comparator byAge para comprobar primero si las edades son iguales y, sino se compara respecto al apellido. El siguiente Comparator hace lo mismo respecto a byAgeAndSurname.
import java.util.*;
class Person {
String name;
String surname;
int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public Integer getAge() {
return this.age;
}
}
public class Main {
public static void main(String[] args) {
Comparator<Person> byAge = Comparator.comparing(
(Person p) -> p.getAge()
);
Comparator<Person> byAgeAndSurname = byAge.thenComparing(
(Person p) -> p.getSurname()
);
Comparator<Person> byAgeAndSurnameAndName = byAgeAndSurname.thenComparing(
(Person p) -> p.getName()
);
Person p1 = new Person("Paco", "Lopez", 10);
Person p2 = new Person("Pepe", "Lopez", 10);
Person p3 = new Person("Juan", "Perez", 10);
System.out.println(byAgeAndSurnameAndName.compare(p1, p2));
System.out.println(byAgeAndSurname.compare(p1, p2));
System.out.println(byAge.compare(p1, p2));
}
}
import java.util.*;
class Person {
String name;
String surname;
int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public Integer getAge() {
return this.age;
}
}
public class Main {
public static void main(String[] args) {
Comparator<Person> byAge = Comparator.comparing(Person::getAge);
Comparator<Person> byAgeAndSurname = byAge.thenComparing(Person::getSurname);
Comparator<Person> byAgeAndSurnameAndName = byAgeAndSurname.thenComparing(Person::getName);
Person p1 = new Person("Paco", "Lopez", 10);
Person p2 = new Person("Pepe", "Lopez", 10);
Person p3 = new Person("Juan", "Perez", 10);
System.out.println(byAgeAndSurnameAndName.compare(p1, p2));
System.out.println(byAgeAndSurname.compare(p1, p2));
System.out.println(byAge.compare(p1, p2));
}
}
import java.util.*;
class Person {
String name;
String surname;
int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public Integer getAge() {
return this.age;
}
}
public class Main {
public static void main(String[] args) {
Comparator<Person> byAgeAndSurnameAndName =
Comparator.comparing(Person::getAge)
.thenComparing(Person::getSurname)
.thenComparing(Person::getName);
Person p1 = new Person("Paco", "Lopez", 10);
Person p2 = new Person("Pepe", "Lopez", 10);
Person p3 = new Person("Juan", "Perez", 10);
System.out.println(byAgeAndSurnameAndName.compare(p1, p2));
}
}