В 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());
Обратите внимание, что хэш-набор создается только один раз: ссылка на метод привязана к его методу contains. То же самое с лямбда-выражением потребует наличия набора в переменной. Создание переменной - неплохая идея, особенно если вы находите ее неприглядной или трудной для понимания.
Вы не можете легко отрицать предикат без чего-то вроде этого служебного метода (или явного приведения), поскольку вы не можете напрямую вызвать ссылку на метод отрицания (сначала требуется вывод типа).
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));