Entendendo a diferença entre ordenado e sorted em Java
Na prática, a pergunta "qual classe implementa uma lista ordenada em Java" carrega uma confusão clássica que vejo todo dia. A própria API do Java separa esses conceitos de forma que quem está começando quase sempre caí no mesmo erro. Vou explicar como funciona na realidade, sem rodeio. O que a maioria das pessoas procura é a classe que mantém os elementos em ordem crescente automaticamente. A resposta direta é TreeSet para conjuntos ordenados e TreeMap para mapas ordenados por chave. Se o objetivo é realmente uma lista (que permite duplicatas e preserva ordem de inserção além de ordem classificatória), nenhuma coleção da biblioteca padrão faz isso sozinha — você precisa combinar uma lista com um processo de ordenação manual.
no java a classe que implementa uma lista ordenada
O TreeSet usa uma árvore avermelhada (red-black tree) por baixo. Isso significa que cada inserção, remoção e busca custa O(log n). Na prática, para coleções pequenas até uns mil elementos, a diferença de performance é imperceptível. Acima disso, você começa a sentir o custo comparado a manter um ArrayList simples e ordenar sob demanda. Aqui vai um exemplo direto do que funciona:
List<Integer> lista = new ArrayList<>(); Isso ordena a lista usando o algoritmo TimSort. Simples, eficiente para a maioria dos casos, e o resultado final é exatamente o que você espera: [1, 2, 5, 9]. O TimSort é estável, o que significa que elementos iguais mantêm a ordem relativa original. Esse detalhe é importante e muitas vezes esquecido.
lista.add(5);
lista.add(2);
lista.add(9);
lista.add(1);
Collections.sort(lista);
Se você precisar de ordenação automática a cada inserção, aí sim o TreeSet é a escolha certa: TreeSet<Integer> conjuntoOrdenado = new TreeSet<>();
conjuntoOrdenado.add(5);
conjuntoOrdenado.add(2);
conjuntoOrdenado.add(9);
conjuntoOrdenado.add(1);
// conjuntoOrdenado = [1, 2, 5, 9]
👉 Clique no botão abaixo para saber mais sobre o assunto!
Note que duplicatas são descartadas. Se isso não te importa, ótimo. Se importa, o TreeSet não é a ferramenta certa. Outro ponto que todo mundo deixa passar: a ordenação no TreeSet depende do natural ordering dos elementos ou de um Comparator fornecido no construtor. Se você putar objetos customizados sem definir nada disso, recebe ClassCastException na primeira inserção. Isso acontece porque o TreeSet precisa comparar os elementos a cada operação para manter a propriedade da árvore balanceada. Sem uma regra de comparação definida, ele simplesmente não funciona.
Pegadinhas que eu aprendi na prática
Eu tive um problema bem específico certa vez trabalhando com um sistema de filas de processamento. Eu estava usando TreeSet com objetos customizados que implementavam Comparable. Até aí, tudo certo. O problema surgiu quando eu precisei remover um elemento que já havia sido modificado após a inserção. A coisa toda quebrou porque o TreeSet não recalcula a posição do elemento quando você altera campos que participam da ordenação. Ele usa o hashCode e a comparação no momento da inserção e assume que aquilo não vai mudar. A solução foi simples na teoria e chata na execução: removi o objeto, fiz a modificação, e inseri de novo. Funcionou, mas exige consciência de que você está lidando com uma estrutura que não suporta mutação dos campos de ordenação.
Outra limitação séria do TreeSet: a operação iterator() retorna os elementos em ordem natural, mas você perde acesso ao índice posicional. Se seu sistema precisa de "me dê o terceiro elemento mais rápido", TreeSet não é eficiente para isso. A complexidade de acesso por índice é O(n) porque a estrutura é uma árvore, não um array. Um ArrayList ordenado resolve isso em O(1).
Quando usar cada abordagem
Se você precisa de uma coleção que cresce e permanece ordenada sem esforço manual, TreeSet é a resposta. Inserir, remover e consultar "qual o menor", "qual o maior", "existe este elemento" são todas operações O(log n). Para consultas de faixa (between queries), o método subSet() é extremamente útil e performático. Se você tem dados que chegam em lote e depois são consultados, ordene uma vez com Collections.sort() e trate como lista imutável depois. Esse padrão costuma ser mais rápido do que manter TreeSet desde o início, porque o custo amortizado de ordenar um array grande é menor do que O(log n) por inserção repetida.
Para listas que precisam manter duplicatas e ainda assim serem ordenadas, a estratégia mais limpa é: colecionar em ArrayList, ordenar com Collections.sort() quando necessário, e aceitar que a ordenação é um passo discreto, não contínuo. Isso é intencional na API do Java — eles não criaram uma "SortedArrayList" porque a combinação de estado mutável com ordenação contínua gera mais problemas do que resolve. Existe também a opção de usar bibliotecas de terceiros como Eclipse Collections ou Trove, que oferecem tipos primitivos ordenados com performance superior em cenários de muitos milhões de elementos. Mas para a grande maioria dos projetos, a stdlib do Java é suficiente.