在带有流的 Java 8 中,实际上非常简单。编辑:可以在没有流的情况下高效,见下文。
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());
请注意,哈希集只创建一次:方法引用与其包含方法相关联。对 lambda 执行相同操作需要将集合放入变量中。制作变量并不是一个坏主意,尤其是当您发现它不美观或难以理解时。
如果没有这种实用方法(或显式强制转换),您将无法轻松 negate the predicate,因为您无法直接调用否定方法引用(首先需要类型推断)。
private static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
如果流有 filterOut 方法或其他东西,它会看起来更好。
另外,@Holger 给了我一个想法。 ArrayList 的 removeAll 方法针对多次删除进行了优化,它只重新排列其元素一次。但是,它使用给定集合提供的contains 方法,所以如果listA 不是很小的,我们需要优化该部分。
使用之前声明的listA 和listB,此解决方案不需要Java 8,而且非常高效。
List<String> result = new ArrayList(listB);
result.removeAll(new HashSet<>(listA));