Al trabajar con colecciones en Java, es común necesitar realizar operaciones como encontrar la diferencia entre dos listas. Una forma directa de lograr esto es utilizando el método removeAll() disponible en la interfaz List.
Sin embargo, la experiencia práctica puede revelar comportamientos inesperados. Consideremos un ejemplo simple para ilsutrar esto:
import java.util.Arrays;
import java.util.List;
public class ListDifferenceTest {
public void demonstrateIssue() {
List<integer> primaryList = Arrays.asList(1, 1, 2, 2, 3, 3, 4);
List<integer> elementsToRemove = Arrays.asList(1, 2, 3);
primaryList.removeAll(elementsToRemove);
System.out.println("Resultado inesperado: " + primaryList);
}
public static void main(String[] args) {
new ListDifferenceTest().demonstrateIssue();
}
}
</integer></integer>
Al ejecutar este código, el resultado puede ser desconcertante:
Resultado inesperado: [1, 1, 2, 2, 3, 3, 4]
Para entender por qué ocurre esto, probemos con una implementación diferente de las listas:
import java.util.ArrayList;
import java.util.List;
public class ListDifferenceTest {
public void demonstrateCorrectBehavior() {
List<integer> primaryList = new ArrayList<>();
primaryList.add(1);
primaryList.add(1);
primaryList.add(2);
primaryList.add(2);
primaryList.add(3);
primaryList.add(3);
primaryList.add(4);
List<integer> elementsToRemove = new ArrayList<>();
elementsToRemove.add(1);
elementsToRemove.add(2);
elementsToRemove.add(3);
primaryList.removeAll(elementsToRemove);
System.out.println("Resultado esperado: " + primaryList);
}
public static void main(String[] args) {
new ListDifferenceTest().demonstrateCorrectBehavior();
}
}
</integer></integer>
Esta vez, la salida es la esperada:
Resultado esperado: [4]
La diferencia clave radica en cómo se crearon las listas en cada caso. El método estático Arrays.asList() devuelve una lista de tamaño fijo y no modificable (en términos de adición o eliminación de elementos). Internamente, Arrays.asList() utiliza una clase anidada lamada ArrayList (que no es la misma que java.util.ArrayList) y su implementación no soporta operaciones de modificación como removeAll() de manera esperada.
En contraste, al usar new ArrayList<>(), se crea una instancia de la implementación estándar y modificable de ArrayList de java.util, la cual sí maneja correctamente el método removeAll().
Por lo tanto, cuando necesite modificar una lista después de crearla usando Arrays.asList(), es recomendable convertirla primero a una instanica de java.util.ArrayList:
List<Integer> modifiableList = new ArrayList<>(Arrays.asList(1, 1, 2, 2, 3, 3, 4));
List<Integer> toRemove = Arrays.asList(1, 2, 3);
modifiableList.removeAll(toRemove);
System.out.println(modifiableList); // Output: [4]