In Java 8 with streams, it's pretty simple actually. EDIT: Can be efficient without streams, see lower.
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());
Note that the hash set is only created once: The method reference is tied to its contains method. Doing the same with lambda would require having the set in a variable. Making a variable is not a bad idea, especially if you find it unsightly or harder to understand.
You can't easily negate the predicate without something like this utility method (or explicit cast), as you can't call the negate method reference directly (type inference is needed first).
private static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
If streams had a filterOut
method or something, it would look nicer.
Also, @Holger gave me an idea. ArrayList
has its removeAll
method optimized for multiple removals, it only rearranges its elements once. However, it uses the contains
method provided by given collection, so we need to optimize that part if listA
is anything but tiny.
With listA
and listB
declared previously, this solution doesn't need Java 8 and it's very efficient.
List<String> result = new ArrayList(listB);
result.removeAll(new HashSet<>(listA));