Como domar o caos: ordenando ArrayList de objetos por qualquer campo em Java
\n\nImagine: você está escrevendo um aplicativo para um catálogo de livros. Você tem uma classe Book com os campos title, author, price e year. Você coloca dezenas de livros em um ArrayList. E então o usuário pede: "Mostre primeiro os mais novos!", e um minuto depois — "Não, ordene por preço!".
Se você já enfrentou esse problema, sabe que simplesmente chamar Collections.sort(list) não funciona. O Java não lê mentes. Você precisa explicar a ele: por qual campo exatamente ordenar. É exatamente sobre isso — a pergunta mais popular no Stack Overflow sobre ordenação de objetos personalizados.
Neste artigo, abordaremos todas as formas de ordenar um ArrayList por uma propriedade do objeto: desde o clássico Comparable até elegantes expressões lambda e Stream API. Vamos nessa!
Preparação: a classe que vamos ordenar
\n\nPara os exemplos, criaremos uma classe simples Person:
public class Person {\n private String name;\n private int age;\n private double salary;\n\n public Person(String name, int age, double salary) {\n this.name = name;\n this.age = age;\n this.salary = salary;\n }\n\n // Getters (setters omitidos para brevidade)\n public String getName() { return name; }\n public int getAge() { return age; }\n public double getSalary() { return salary; }\n\n @Override\n public String toString() {\n return name + " (" + age + " anos, $" + salary + ")";\n }\n}\n\n\nE vamos preencher nossa lista:
\n\nArrayList<Person> people = new ArrayList<>();\npeople.add(new Person("Ana", 28, 55000));\npeople.add(new Person("Bruno", 35, 72000));\npeople.add(new Person("Carlos", 22, 48000));\npeople.add(new Person("Diana", 30, 62000));\n\n\nAgora tudo está pronto para os experimentos. Como ordenar esta lista por idade? Por nome? Por salário? O Java tem pelo menos três maneiras. Vamos começar pela fundamental.
\n\nMétodo 1: Comparable — incorporando a lógica de ordenação diretamente na classe
\n\nA interface Comparable é a "ordem natural" do objeto. Se você deseja que seus objetos sejam sempre ordenados por um campo (por exemplo, idade), implemente esta interface.
Vamos modificar nossa classe Person:
public class Person implements Comparable<Person> {\n // ... campos, construtor, getters ...\n\n @Override\n public int compareTo(Person other) {\n return Integer.compare(this.age, other.age);\n }\n}\n\n\nAgora a ordenação é uma linha:
\n\nCollections.sort(people);\nSystem.out.println(people);\n// Saída: [Carlos (22 anos, $48000), Ana (28 anos, $55000), Diana (30 anos, $62000), Bruno (35 anos, $72000)]\n\n\nVantagens: simplicidade, não precisa pensar em comparadores externos.
\nDesvantagens: você "fixa" na classe apenas uma forma de ordenação. Se amanhã precisar ordenar por nome — terá que alterar a classe.
A propósito, para ordem inversa (do maior para o menor), você pode usar Collections.reverseOrder():
Collections.sort(people, Collections.reverseOrder());\n\n\nMétodo 2: Comparator — flexibilidade sem alterar a classe
\n\nQuando você precisa ordenar de maneiras diferentes em diferentes partes do programa, o Comparator vem ao resgate. É uma classe separada ou classe anônima que contém a lógica de comparação.
Classe anônima — método do avô
\n\nCollections.sort(people, new Comparator<Person>() {\n @Override\n public int compare(Person p1, Person p2) {\n return p1.getName().compareTo(p2.getName());\n }\n});\n\n\nFunciona, mas parece verboso. Em