Comparar Objectos

Muitas vezes preciso de ir à base de dados e preencher listas (ou arrays) com objectos do tipo VO
(View Objects) para depois mostrar numa página web. Tenho necessidade de ordenar essa
lista baseado num critério qualquer. Supponhamos a seguinte situação: na base de dados
há uma tabela de pessoas com as colunas firstName, lastName, e age
e quero prencher uma lista com objectos do tipo Person:

public class Person {
	private String firstName;
	private String lastName;
	private int age;

	public String getFirstName() {
		return firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public int getAge() {
		return age;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

Suponhamos agora que tenho um Array carregado com objectos do tipo Person
(com 3 objectos, por exemplo):

 /**
 * Hardcoded mas normalmente vem da base de dados sob a forma de resultset
 */
 		Person[] persons = new Person[3];
		persons[0] = new Person();
		persons[0].setFirstName("Marcus");
		persons[0].setLastName("Miller");
		persons[0].setAge(43);

		persons[1] = new Person();
		persons[1].setFirstName("Stanley");
		persons[1].setLastName("Clark");
		persons[1].setAge(35);

		persons[2] = new Person();
		persons[2].setFirstName("Jaco");
		persons[2].setLastName("Pastorious");
		persons[2].setAge(38);

Portanto, o que eu quero é ordenar este array por, digamos, primeiro nome ou idade.
Se utilizar o método sort da classe java.util.Arrays:

		 Arrays.sort(persons);

não funciona (envia uma excepção do tipo ClassCastException.
Naturalmente que posso escrever um algorítmo específico (tipo bubble sort) para ordenar
o array mas esta solução não é prática. A solução correcta passa por utilizar
o java.lang.Comparable interface. Implementando este interface,
torno as instâncias das classes comparáveis de acordo com critérios por mim definidos.

Vamos, então, implementar o interface Comparable. Este interface tem um
método, CompareTo, que determina como comparar duas instâncias
da classe. A sua assinatura é:

		 public int CompareTo(Object o)

que aceita como argumento um Object. Claro que só faz
sentido comparar instâncias do mesmo tipo. Podemos ver, também, que retorna um
inteiro que é igual a zero se o objecto passado é igual a esta instância e retorna
um inteiro positivo ou negativo se este objecto é maior ou menor do que o objecto
passado, respectivamente. Suponhamos que o critério de ordenação é a idade da pessoa:
A nossa classe Person fica assim:

public class Person implements Comparable{
	private String firstName;
	private String lastName;
	private int age;

	public String getFirstName() {
		return firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public int getAge() {
		return age;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int compareTo(Object anotherPerson) throws ClassCastException{
		if(!(anotherPerson instanceof Person))
			throw new ClassCastException("Objecto do tipo Person esperado!");
		int anotherPersonAge = ((Person)anotherPerson).getAge();
		return this.age - anotherPersonAge;
	}
}

Assim, se quiser ordenar o array por idades crescente, só tenho de fazer
Arrays.sort(Person).
Podemos testar:

public static void main(String[] args) {
		Person[] persons = new Person[3];
		persons[0] = new Person();
		persons[0].setFirstName("Marcus");
		persons[0].setLastName("Miller");
		persons[0].setAge(43);

		persons[1] = new Person();
		persons[1].setFirstName("Stanley");
		persons[1].setLastName("Clark");
		persons[1].setAge(35);

		persons[2] = new Person();
		persons[2].setFirstName("Jaco");
		persons[2].setLastName("Pastorious");
		persons[2].setAge(38);
		System.out.println("ORDEM NATURAL:");
		for(int i = 0; i < persons.length; i++){
			System.out.println(persons[i].getFirstName() + ", " +
                        persons[i].getLastName() + "," + persons[i].getAge());
		}
		Arrays.sort(persons);
		System.out.println("ORDENADO POR IDADE");
		for(int i = 0; i < persons.length; i++){
			System.out.println(persons[i].getFirstName() + ", " +
                        persons[i].getLastName() + "," + persons[i].getAge());
		}
}

e o output é o esperado:

ORDEM NATURAL:
Marcus, Miller,43
Stanley, Clark,35
Jaco, Pastorious,38
ORDENADO POR IDADE
Stanley, Clark,35
Jaco, Pastorious,38
Marcus, Miller,43

Se quiser ordenar, não por idade mas por, digamos, primeiro nome, só tenho de
adaptar o meu método CompareTo:

	public int compareTo(Object anotherPerson) throws ClassCastException{
		if(!(anotherPerson instanceof Person))
			throw new ClassCastException("Objecto do tipo Person esperado!");
		String anotherPersonFirstName = ((Person)anotherPerson).getFirstName();
		return this.firstName.compareTo(anotherPersonFirstName);
	}

E se eu quiser ter alguma flexibilidade no código para ordenar ou por idade, ou
por primeiro nome ou por último nome, conforme a situação? isso será matéria
para o próximo post (iremos implementar o interface java.util.Comparator

Deixar uma Resposta