En Java 8 con streams, en realidad es bastante simple. EDITAR: Puede ser eficiente sin flujos, ver más abajo.
List<String> listA = Arrays.asList("2009-05-18","2009-05-19","2009-05-21");
List<String> listB = Arrays.asList("2009-05-18","2009-05-18","2009-05-19","2009-05-19",
"2009-05-20","2009-05-21","2009-05-21","2009-05-22");
List<String> result = listB.stream()
.filter(not(new HashSet<>(listA)::contains))
.collect(Collectors.toList());
Tenga en cuenta que el conjunto de hash solo se crea una vez: la referencia del método está vinculada a su método contiene. Hacer lo mismo con lambda requeriría tener el conjunto en una variable. Hacer una variable no es una mala idea, especialmente si le resulta desagradable o más difícil de entender.
No puede negar fácilmente el predicado sin algo como este método de utilidad (o conversión explícita), ya que no puede llamar directamente a la referencia del método negado (primero se necesita la inferencia de tipo).
private static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
Si las transmisiones tuvieran un filterOutmétodo o algo, se vería mejor.
Además, @Holger me dio una idea. ArrayListtiene su removeAllmétodo optimizado para múltiples eliminaciones, solo reorganiza sus elementos una vez. Sin embargo, utiliza el containsmétodo proporcionado por la colección dada, por lo que necesitamos optimizar esa parte si listAes cualquier cosa menos pequeña.
Con listAy listBdeclarado previamente, esta solución no necesita Java 8 y es muy eficiente.
List<String> result = new ArrayList(listB);
result.removeAll(new HashSet<>(listA));