Como Remover Duplicatas de uma Lista em Java
Remova duplicatas de uma lista Java com HashSet, LinkedHashSet ou stream distinct.
Uma List em Java permite elementos duplicados por design, então quando você precisa que cada valor apareça apenas uma vez, é necessário remover as repetições manualmente. Este capítulo mostra as formas idiomáticas de fazer isso, com atenção a se a ordem de inserção original é preservada.
Usando um LinkedHashSet (ordem preservada)
A abordagem mais limpa é copiar a lista para um set, pois um Set rejeita duplicatas automaticamente. Use LinkedHashSet em vez de um simples HashSet para que a ordem de primeira ocorrência dos elementos seja mantida:
List<String> unique = new ArrayList<>(new LinkedHashSet<>(list));Envolver o set novamente em um ArrayList devolve uma List, pronta para indexação ou trabalhos posteriores. O LinkedHashSet faz todo o trabalho pesado: ao ser preenchido a partir da lista original, ele descarta silenciosamente qualquer elemento que já tenha visto, enquanto sua estrutura encadeada lembra a ordem em que os elementos chegaram pela primeira vez.
Se você não se importa com a ordem, um HashSet simples é marginalmente mais rápido e usa um pouco menos de memória. Porém, ele embaralha a ordem dos elementos, o que raramente é o desejado ao exibir uma lista, então LinkedHashSet é o padrão seguro.
Usando a Stream API
A partir do Java 8, Stream.distinct() remove duplicatas em um pipeline único e legível. Assim como o LinkedHashSet, ele mantém a ordem de encontro dos elementos:
List<String> unique = list.stream()
.distinct()
.collect(Collectors.toList());distinct() compara elementos com equals() e hashCode(), exatamente como um set faz, então seus objetos devem implementar esses métodos corretamente para tipos personalizados. Essa forma brilha quando a deduplicação é um passo em um pipeline maior — você pode encadear filter, map ou sorted ao redor dela sem introduzir uma coleção temporária.
Comparando as abordagens
Ambas as técnicas comuns dependem de equals/hashCode e ambas preservam a ordem de inserção; a diferença é principalmente de estilo e contexto.
| Abordagem | Ordem mantida? | Melhor quando |
|---|---|---|
LinkedHashSet | Sim | Um one-liner rápido e sem dependências |
HashSet | Não | A ordem não importa e a velocidade é crítica |
stream().distinct() | Sim | A deduplicação faz parte de um pipeline de stream maior |
Um ponto importante para todos eles: eles constroem uma nova coleção em vez de mutar a fonte. Se você precisar deduplicar no lugar, pode limpar a lista e re-adicionar os elementos únicos, ou atribuir o resultado de volta à mesma variável.
Exemplo prático
O que observar na execução:
- A lista original mantém todos os 7 elementos, incluindo os
javaesqlrepetidos, pois umaListpermite duplicatas. - O resultado do
LinkedHashSettem apenas 4 elementos —[java, sql, api, rest]— e eles aparecem na ordem de primeira ocorrência, sem ordenação ou embaralhamento. - O resultado de
stream().distinct()é idêntico em tamanho e ordem, confirmando que as duas técnicas são intercambiáveis aqui. deduped.equals(viaStream)imprimetrue, pois duas listas são iguais quando contêm os mesmos elementos na mesma ordem.- A lista original
tagspermanece inalterada, então as operações de deduplicação produziram novas listas em vez de mutar a fonte.