Cómo eliminar duplicados de una lista en Java
Elimina duplicados de una lista Java usando HashSet, LinkedHashSet o stream().distinct().
Una List en Java permite elementos duplicados por diseño, por lo que cuando necesitas que cada valor aparezca solo una vez debes eliminar las repeticiones tú mismo. Este capítulo muestra las formas idiomáticas de hacerlo, con atención a si se conserva el orden de inserción original.
Usando un LinkedHashSet (orden preservado)
El enfoque más limpio es copiar la lista en un conjunto, ya que un Set rechaza duplicados automáticamente. Usa LinkedHashSet en lugar de un HashSet simple para que se conserve el orden de los elementos según la primera vez que fueron vistos:
List<String> unique = new ArrayList<>(new LinkedHashSet<>(list));Envolver el conjunto de nuevo en un ArrayList te da una List otra vez, lista para indexar o continuar trabajando. El LinkedHashSet hace todo el trabajo pesado: al llenarse con la lista original descarta silenciosamente cualquier elemento que ya haya visto, mientras que su estructura enlazada recuerda el orden en que los elementos llegaron por primera vez.
Si no te importa el orden, un HashSet simple es marginalmente más rápido y usa un poco menos de memoria. Sin embargo, revuelve el orden de los elementos, lo cual rara vez es lo que deseas al mostrar una lista, por lo que LinkedHashSet es la opción segura por defecto.
Usando la Stream API
A partir de Java 8, Stream.distinct() elimina duplicados en un pipeline único y legible. Al igual que LinkedHashSet, conserva el orden de encuentro de los elementos:
List<String> unique = list.stream()
.distinct()
.collect(Collectors.toList());distinct() compara elementos con equals() y hashCode(), exactamente como lo hace un conjunto, por lo que tus objetos deben implementar esos métodos correctamente para tipos personalizados. Esta forma destaca cuando la deduplicación es un paso dentro de un pipeline más grande — puedes encadenar filter, map o sorted a su alrededor sin introducir una colección temporal.
Comparando los enfoques
Ambas técnicas comunes se basan en equals/hashCode y ambas preservan el orden de inserción; la diferencia es principalmente de estilo y contexto.
| Enfoque | ¿Orden conservado? | Mejor cuando |
|---|---|---|
LinkedHashSet | Sí | Una línea rápida sin dependencias externas |
HashSet | No | El orden no importa y la velocidad es crítica |
stream().distinct() | Sí | La deduplicación es parte de un pipeline stream más grande |
Un punto clave para todos ellos: crean una colección nueva en lugar de mutar la original. Si necesitas deduplicar en el lugar, puedes limpiar la lista y volver a agregar los elementos únicos, o asignar el resultado de vuelta a la misma variable.
Ejemplo práctico
Lo que se puede extraer de la ejecución:
- La lista original conserva los 7 elementos, incluidos los
javaysqlrepetidos, porque unaListpermite duplicados. - El resultado del
LinkedHashSettiene solo 4 elementos —[java, sql, api, rest]— y aparecen en el orden en que fueron vistos por primera vez, no ordenados ni mezclados. - El resultado de
stream().distinct()es idéntico tanto en tamaño como en orden, confirmando que las dos técnicas son intercambiables en este caso. deduped.equals(viaStream)imprimetrue, ya que dos listas son iguales cuando contienen los mismos elementos en el mismo orden.- La lista original
tagsno cambia, por lo que las operaciones de deduplicación produjeron listas nuevas en lugar de mutar la original.