Ordenando coleções com Comparable & Comparator
Com certeza em algum momento você já se deparou com a necessidade de ordenar algum tipo de lista ou mesmo um array, e teve duvidas de como fazer isso. O Java fornece a classe java.util.Collections
e seu método sort()
, que são capazes de ordenar uma lista e a classe java.util.Arrays.sort()
para ordenação de arrays. Porém, para fazer uso deste recurso é necessário ainda informar os critérios que serão usados na ordenação.
Existem duas interfaces para configurar estes critérios, a interface java.lang.Comparable
e a interface java.util.Comparator
. Vamos agora criar uma classe chamada Person
– Listagem 1 – a qual contem dois atributos: name
(String) e age
(int).
package com.mballem.tutorial; /** * Created by IntelliJ IDEA. * User: Marcio Ballem * Date: 29/07/13 * Time: 14:47 * https://www.mballem.com/ */ public class Person implements Comparable{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } String getName() { return name; } int getAge() { return age; } @Override public String toString() { return "n" + "Person{name='" + name + ", age='" + age + "}"; } }
Agora, vamos usar a classe Main para realizar alguns testes. No método main()
existe uma lista, chamada persons, a qual na execução do código ira ser impressa no console pelo método printer()
.
package com.mballem.tutorial; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Created by IntelliJ IDEA. * User: Marcio Ballem * Date: 29/07/13 * Time: 14:52 * https://www.mballem.com/ */ public class Main { public static void main(String[] args) { Listpersons = new ArrayList (); persons.add(new Person("Carla Maria", 20)); persons.add(new Person("Diogo Flores", 22)); persons.add(new Person("Marta Rios", 32)); persons.add(new Person("Julia Peres", 25)); persons.add(new Person("Aline Pereira", 23)); persons.add(new Person("Bianca Jasmim", 19)); Main.printer(persons); } private static void printer(List persons) { System.out.println(persons.toString()); } }
O resultado do método printer()
terá como saída o resultado abaixo. Note que como não usamos nenhum tipo de ordenação, a lista foi impressa exatamente na mesma ordem em que seus elementos foram adicionados no método main()
.
[ Person{name='Carla Maria', age=20}, Person{name='Diogo Flores', age=22}, Person{name='Marta Rios', age=32}, Person{name='Julia Peres', age=25}, Person{name='Aline Pereira', age=23}, Person{name='Bianca Jasmim', age=19} ]
Vamos fazer agora uma ordenação por idade, ou seja, pelo atributo age. Desta forma, quando a lista for novamente impressa no console, os elementos devem estar ordenados em ordem crescente (0 – 9). Primeiro devemos fazer duas alterações na classe Person
. Observe na Listagem 3 que adicionamos a assinatura da classe Person
a interface java.lang.Comparable
. Por adicionar esta interface, devemos implementar o seu método compareTo()
. Será neste método que vamos definir a ordenação por idade.
public class Person implements Comparable{ //códigos anteriores omitidos. public int compareTo(Person person) { if (this.age < person.age) { return -1; } if (this.age > person.age) { return 1; } return 0; } }
O método compareTo()
tem como retorno um int com as seguintes características:
- Valor negativo, se this.object < parâmetro;
- Valor positivo, se this.object > parâmetro;
- Valor zero, se this.object for igual ao parâmetro.
O retorno deste método é que vai classificar se o objeto atual da lista ou de um array é menor, maior ou igual ao objeto anterior, e assim, a classificação é realizada. Retornando a classe Main
, adicione uma chamada a um novo método da classe chamado sortByAge()
, descrito na Listagem 4.
public class Main { public static void main(String[] args) { Listpersons = new ArrayList (); persons.add(new Person("Carla Maria", 20)); persons.add(new Person("Diogo Flores", 22)); persons.add(new Person("Marta Rios", 32)); persons.add(new Person("Julia Peres", 25)); persons.add(new Person("Aline Pereira", 23)); persons.add(new Person("Bianca Jasmim", 19)); Main.sortByAge(persons); } private static void sortByAge(List persons) { Collections.sort(persons); System.out.println(persons.toString()); } }
Neste método adicionamos persons como parâmetro no método sort()
da classe Collections
e em seguida, a lista será impressa no console. O método sort()
usará o método compareTo() da classe Persons
para realizar a ordenação. Veja o que será impresso no console desta vez, e repare que a ordenação foi realizada em ordem crescente de idade.
[ Person{name='Bianca Jasmim', age=19}, Person{name='Carla Maria', age=20}, Person{name='Diogo Flores', age=22}, Person{name='Aline Pereira', age=23}, Person{name='Julia Peres', age=25}, Person{name='Marta Rios', age=32} ]
O passo seguinte será criar uma ordenação por nome, usando o atributo name
. Para realizar a ordenação por nome, vamos criar uma classe chamada PersonComparator
– Listagem 5 – e implementar a interface Comparator
. A interface requer a implementação do método compare()
. Este método recebe dois parâmetros, os quais serão utilizados para a comparação entre os atributos name da lista.
package com.mballem.tutorial; import java.util.Comparator; /** * Created by IntelliJ IDEA. * User: Marcio Ballem * Date: 29/07/13 * Time: 15:11 * https://www.mballem.com/ */ public class PersonComparator implements Comparator{ public int compare(Person p1, Person p2) { return p1.getName().compareTo(p2.getName()); } }
Na classe Main
– Listagem 6 – vamos adicionar o método sortByName()
para visualizar o resultado. Note, que desta vez, o método Collections.sort()
recebeu um segundo parâmetro, que nada mais é que uma instancia da classe PersonComparator
.
package com.mballem.tutorial; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Created by IntelliJ IDEA. * User: Marcio Ballem * Date: 29/07/13 * Time: 14:52 * https://www.mballem.com/ */ public class Main { public static void main(String[] args) { Listpersons = new ArrayList (); persons.add(new Person("Carla Maria", 20)); persons.add(new Person("Diogo Flores", 22)); persons.add(new Person("Marta Rios", 32)); persons.add(new Person("Julia Peres", 25)); persons.add(new Person("Aline Pereira", 23)); persons.add(new Person("Bianca Jasmim", 19)); Main.sortByName(persons); } private static void sortByName(List persons) { Collections.sort(persons, new PersonComparator()); System.out.println(persons.toString()); } }
Como saída no console teremos o resultado abaixo. Observe que desta vez a ordenação ocorreu de forma alfabética de a – z.
[ Person{name='Aline Pereira', age=23}, Person{name='Bianca Jasmim', age=19}, Person{name='Carla Maria', age=20}, Person{name='Diogo Flores', age=22}, Person{name='Julia Peres', age=25}, Person{name='Marta Rios', age=32} ]
Como temos também uma ordenação por idade, caso tivéssemos dois ou mais nomes iguais e com idades diferentes, a ordenação seria por nome e por idade na sequência, como mostra o exemplo abaixo:
[ Person{name='Aline Pereira, age='23}, Person{name='Bianca Jasmim, age='19}, Person{name='Carla Maria, age='20}, Person{name='Maria Rios, age='29}, Person{name='Maria Rios, age='30}, Person{name='Marta Rios, age='32}, Person{name='Zilo Pires, age='21} ]
A classe PersonComparator
só foi criada por que já existia em Person
uma implementação do método compareTo()
. Se fosse necessário order apenas por nome, poderíamos usar o método compareTo()
da interface Comparable
e o método compareTo()
já disponível nos objetos do tipo String
. Na Listagem 7 substituímos a implementação por idade pela implementação por nome. Desta forma, na classe Main basta remover do método sortByName()
a instancia de PersonComparator
que ele ordenará por nome, mas não mais por idade.
package com.mballem.tutorial; /** * Created by IntelliJ IDEA. * User: Marcio Ballem * Date: 29/07/13 * Time: 14:47 * https://www.mballem.com/ */ public class Person implements Comparable{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } String getName() { return name; } int getAge() { return age; } @Override public String toString() { return "n" + "Person{name='" + name + ", age='" + age + "}"; } /*public int compareTo(Person person) { if (this.age < person.age) { return -1; } if (this.age > person.age) { return 1; } return 0; }*/ public int compareTo(Person person) { return this.name.compareTo(person.getName()); } }
Referencias
- Interface Comparable – http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html
- Interface Comparator – http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html