Se você chegou até essa página pelo Google, certamente quer ver logo um exemplo de código para sua aplicação, então primeiro vamos ao código e depois para a explicação, que está muito extensa e detalhada. Se você quiser ler, ou se ocorreu algum problema na adaptação do código para sua aplicação, leia o texto abaixo para entender melhor como as coisas funcionam.
>> Ordenação simples (Números)
Collections.sort(o, new Comparator() {
public int compare(Object x1, Object x2) {
Pessoa p1 = (Pessoa) x1;
Pessoa p2 = (Pessoa) x2;
if (p1.getIdade() < p2.getIdade()) {
return -1;
} else if (p1.getIdade() > p2.getIdade()) {
return 1;
} else {
return 0;
}
}
});
>> Ordenação de String (Lista de String, ou lista de objeto com String).
Collections.sort(o, new Comparator() {
public int compare(Object x1, Object x2) {
Pessoa p1 = (Pessoa) x1;
Pessoa p2 = (Pessoa) x2;
Collator.getInstance().compare(p1.getNome(), p2.getNome());
}
});
Se apenas o código não te ajudou muito e/ou se você deseja se aprofundar mais no assunto, dedique de 5 a 10 minutos ao texto abaixo, ou um pouco mais de tempo se quiser ir praticando os exemplos.
Enquanto estamos aprendendo a programar (se você seguiu todos os passos direito, antes de linguagem aprendeu lógica), vemos alguns algoritmos de ordenação, como quick sort e bubble sort. Também vemos algorítmos de pesquisa, como busca binária e busca linear. Mas depois que deixamos a lógica de lado e começamos a ver alguma linguagem de programação mais recentes, orientada a objetos, eventos, aspectos ou qualquer coisa do tipo, verificamos que esse tipo de algoritmo não é mais necessário, apenas em alguns casos muito específicos. Isso porque as linguagens de hoje em dia já possuem métodos e códigos muito mais rápidos e performáticos para essas situações.
Antes de mais nada, precisamos verificar se existe mesmo a necessidade de ordenar a lista na aplicação, afinal, essa lista veio de algum lugar, e se esse lugar for um banco de dados, é muito melhor fazer um “Order By” no banco do que passar essa tarefa para o java ou qualquer outra linguagem, não importa se o banco de dados é Oracle, Sql, MySql ou mesmo Mainframe, quase todos os banco de dados possuem um order by, até mesmo o finado Access.
Mas nem sempre podemos contar com um banco de dados, as vezes fazemos programas que lêem arquivos, ou recebem informações por socket, webservice ou até mesmo por digitação do usuário.
Quando precisamos ordenar uma lista que não vem de um banco de dados, ou por algum motivo qualquer o banco de dados não consegue/não pode ordenar a lista, então apelamos para a ordenação no java, mas tome muito cuidado, você não precisa criar um algorítimo para ordenar alguma coisa, a própria linguagem tem ferramentas de ordenação que com certeza serão muito melhores que qualquer algorítimo que eu ou você fizermos (já testei e por melhor que fosse meu algorítimo, o do java sempre era milissegundos mais rápido).
Você já ouviu falar em Comparator? E em Comparable? Acho que também não deve conhecer o Collator?
Pois bem, essas são algumas das classes java que nos auxiliam a ordenar uma lista, pode ser uma lista de tipos primitivos ou uma lista de um objeto qualquer, até mesmo uma lista de objetos diferentes, da para ordenar de tudo.
Em muitos lugares você vai ouvir “implemente a classe x e sobrescreva o método y”, mas eu não gosto de fazer isso, eu até faço algumas vezes, mas apenas quando é necessário e apenas quando existir um tipo de ordenação. Deixe-me ser mais claro, imagine que você tem um objeto pessoa, esse objeto tem os atributos nome, idade e cidade. Agora imagine que você tem uma lista de Pessoa (List<Pessoa>), e na sua aplicação o usuário pode escolher ordenação por nome ou por idade ou por cidade.
Para esse caso, se você deixar o seu objeto “comparável”, você vai ter que escolher apenas um atributo para ser a chave da ordenação. Para conseguir realizar os três tipos de ordenação você precisará fazer uma gambiarra ou criar outras classes que servem apenas para indicar que a ordenação agora vai ser por idade, ou por cidade.
Por isso que eu não implemento o comparador, só faço isso quando vou utilizá-lo outras vezes, o que quase nunca acontece.
Se eu não implemento o comparador, o que eu faço?
Eu crio o comparador na hora que eu mando o java ordenar.
Mais ou menos assim:
Java, ordena para mim essa lista e usa esse novo critério que estou definindo agora. (Igual o seu chefe falando com você).
Vamos as explicações práticas!
Primeiro você precisa ter uma lista, de preferencia preenchida.
List<Pessoa> p;
Depois você precisa chamar o método sort da classe java.util.Collections e passar para ele a sua lista.
Collections.sort(p);
Se o seu objeto já é “comparável” (veremos isso mais para frente), apenas isso basta, mas se o seu objeto é “normal”, possui apenas os atributos e métodos básicos que você mesmo criou, então será necessário informar para o sort qual parâmetro de ordenação você escolheu. Nesse ponto, você informa uma classe de comparação que você criou, ou cria os parametros na hora (o que eu costumo fazer).
Collections.sort(p, new Comparator());
Até aqui está tranquilo? Entendendo tudo?
Mas se você escrever apenas isso vai dar um erro, dizendo que não da para instanciar a classe “Comparator“. Isso é verdade, mas nosso código não acabou ainda, como eu disse, precisamos criar os parametros de ordenação.
Imagine que criaremos um método alí dentro do sort.
Collections.sort(p, new Comparator() { });
Captou a mensagem? Agora precisamos escrever algum método dentro do new Comparator() { }.
Mas não pode ser um método qualquer, tem que ser o método compare, que é utilizado pelo Comparator para estabelecer os parâmetros de ordenação.
Collections.sort(o, new Comparator() {
public int compare(Object x1, Object x2) {}
});
Até aqui tudo entendido?
O método compare, da classe Comparator fala para o ordenador qual dos dois objetos recebidos é “maior” e qual é “menor“, isso você que define.
Agora é que a mágica vai acontecer, o compare recebe dois Objects, que podem (e vão) ser do tipo da sua lista, então você faz o “cast“, e compara as variáveis da forma como desejar. Mas calma que não é só isso. Repare no tipo do método compare, ele retorna um int! O que devemos retornar nesse caso?
Se o objeto 1 for MENOR que o objeto 2, então o retorno deve ser -1
Se o objeto 1 for MAIOR que o objeto 2, então o retorno deve ser 1
Senão (objetos iguais), então o retorno deve ser 0;
Guarde muito bem essas informações na sua memória, isso vai ser bem utilizado em praticamente todos os tipos de comparação.
Apenas imagine o seguinte, a posição dos números: … -3, -2, -1, 0, 1, 2, 3 …
Qual número está à esquerda? Obviamente o -1
Qual número está à direita? Novamente óbvio, o número 1
O zero está exatamente no meio dos dois, é “neutro“, não tem diferença.
Agora imagine os parâmetros: public int compare(Object x1, Object x2)
Pense agora em colocar esses objetos na ordem, o objeto menor fica à esquerda e o maior dica à direita (partindo do primeiro objeto).
O x1 é MENOR? Então ele deve ficar na esquerda, então devemos retornar -1.
O x1 é MAIOR? Então ele deve ficar na direita, então devemos retornar 1.
Entendeu?
Então vamos colocar em prática.
Collections.sort(o, new Comparator() {
public int compare(Object x1, Object x2) {
Pessoa p1 = (Pessoa) x1;
Pessoa p2 = (Pessoa) x2;
if (p1.getIdade() < p2.getIdade()) {
return -1;
} else if (p1.getIdade() > p2.getIdade()) {
return 1;
} else {
return 0;
} }
});
Pronto, o código é esse.
Achou simples? Eu acho que podemos complicar mais!
A comparação acima serve apenas para Números. E quando precisamos ordenar TEXTO, o que fazer?
Calma, calma, calma, não há necessidade de apelar para algorítimos, deixa o Java fazer o trabalho sujo para você.
Imagine o mesmo princípio da ordenação por número, nós preparamos o ambiente mas agora vamos deixar o “IF..ELSE” para outro infeliz fazer.
Esse outro infeliz seria o método compare da classe java.text.Collator, essa classe tem muitas utilidades e vários tipos de ordenação muito legais, mas por enquanto o que nos interessa é a ordenação de texto.
O método compare dessa classe funciona exatamente igual ao que fizemos acima, ele recebe dois objetos, para o nosso caso ele recebe duas Strings, e retorna -1, 0 ou 1, exatamente como explicado acima. Então o que devemos fazer é substituir o nosso “IF..ELSE” pelo pelo compare dessa classe.
Collections.sort(o, new Comparator() {
public int compare(Object x1, Object x2) {
Pessoa p1 = (Pessoa) x1;
Pessoa p2 = (Pessoa) x2;
Collator.getInstance().compare(p1.getNome(), p2.getNome());
}
});
Ficou até mais simples…
O que fizemos aqui foi passar a Decisão para outra pessoa (Igual o seu chefe faz com você), no lugar de nós tomarmos a decisão de qual String é maior do que a outra, passamos essa tarefa para o método compare da classe Collator.
Isso é tudo pessoal! Ou melhor, quase tudo.
Fiquei devendo falar das implementações, que eu raramente uso.
Primeiro devo dizer que é raro eu precisar ordenar uma lista, porque trabalhando com banco de dados essa tarefa obviamente não fica com o java, mas quando é necessário ordenar a lista no java dificilmente essa mesma lista precirá ser ordenada novamente, no mesmo modo em outro lugar, mas existem algumas ocasiões em que precisamos ordenar a mesma lista, da mesma forma, na tela a, depois na tela b, e na tela c, etç, etç. Para esses casos é chato, inviável e não recomendável utilizar a ordenação da forma como fiz acima, digo isso porque: Digamos que você fez essa ordenação em 5 lugares diferentes da aplicação, e aplicou esse mesmo código nos cinco lugares. Depois de alguns meses, quase na implantação do projeto, o cliente desiste da ordenação e diz que ficaria melhor de outra forma, então você volta e altera os parâmetros de ordenação, mas você não lembra mais todos os lugares em que a ordenação é realizada, ou pior, você não está mais no projeto, quem vai alterar o código é o novo estagiáro! A casa caiu, certamente alguma(s) das ordenações ficará da forma antiga, o que causará um erro ou insatisfação do cliente, ou os dois.
Pensando nisso, podemos deixar a nossa classe Comparável! Mas o que significa isso? Significa que deixamos uma “marca” na nossa classe, dizendo que ela pode ser ordenada!
Vamos voltar à classe Pessoa:
class Pessoa {
private String nome;
privete String cidade;
private int idade;
//Getters e Setters
}
Essa classe é simples, não tem nada de mais.
Podemos escolher um dos atributos para deixá-la comparável, no caso vou escolher o “mais facil”, onde o controle fica comigo, então vou escolher o inteiro, a idade.
Para marcarmos a classe informando que ela é “Comparável”:
class Pessoa implements Comparable<Pessoa> {}
Na declaração da classe acima, dizemos que a classe Pessoa é comparável com outra classe do tipo Pessoa.
Agora precisamos escrever um método chamado compareTo, que funcioana exatamente igual ao método compare que vimos acima, porém esse método recebe apenas um objeto, afinal o outro objeto é a própria classe.
public int compareTo(Pessoa p) {
if (this.idade < p.getIdade()) {
return -1;
} else if (this.idade > p.getIdade()) {
return 1;
} else {
return 0;
}
}
Como declaramos que a classe Pessoa é comparável com outro objeto do tipo Pessoa, entõ o nosso método compareTo recebe um objeto Pessoa como parâmetro. Se não declararmos na classe o tipo de objeto de comparação, então nosso método compareTo deverá receber um Object, e dentro do método fazemos o cast.
Agora nossa classe está pronta e preparada para ser ordenada por idade, basta você chamar o Collections.sort e ordenar a lista, sem precisar informar nenhum comparador.
Collections.sort(lista);
Mas e se quisermos criar vários tipos de comparação? Então agora você precisará criar classes de comparação!
Crie um comparador para cada tipo de ordenação que quiser fazer.
No nosso exemplo, já preparamos a classe Pessoa para ser ordenada por idade, agora precisamos ordená-la por nome. Então criamos uma nova classe no nosso projeto e implementamos o java.util.Comparator, ao implementar essa classe você será obrigado a escrever o método compare e, adivinha? Ele funciona exatamente igual o primeiro compare que escrevemos, deve retornar -1, 0 ou 1.
Esse método vai receber dois objetos. Se você declarou o tipo do objeto na assinatura da classe, então o método vai receber o tipo que você refiniu, caso contrário ele vai receber dois Objects.
class ComparadorNome implements Comparator <Pessoa>{
public int compare(Pessoa o1, Pessoa o2) {
return Collator.getInstance().compare(o1.getNome(), o2.getNome());
}
}
Fácil?
Agora na hora de ordenar, você fala para o Java mais ou menos assim:
Java, querido amigo, eu quero que você ordene essa lista, eu sei que ela está preparada para ser ordenada por idade, mas eu quero que você utilize esse outro parâmetro que eu encontrei jogado por ali e achei legal.
Isso em código fica dessa forma: Collections.sort(lista, new ComparadorNome());
Eu optei por deixar a classe preparada para ser ordenada por idade e criar um comparador para nome, mas você pode fazer o contrário, pode fazer o que quiser, com as váriáveis que achar melhor! Agora você já pode ordenar uma lista utilizando o atributo que achar melhor, e quantos atributos quiser.
Se ficou alguma dúvida, ou algum código não funcionou (eu testei!), pergunta ai.