В 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));