У Java 8 з потоками це насправді досить просто. EDIT: Може бути ефективним без потоків, див. Нижче.
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());
Зверніть увагу, що хеш-набір створюється лише один раз: посилання на метод прив’язане до методу містить. Для того, щоб зробити те саме з лямбда, потрібно мати набір змінних. Створення змінної - це не погана ідея, особливо якщо вам здається, що це неестетично або важче зрозуміти.
Ви не можете легко заперечити предикат без чогось подібного до цього методу утиліти (або явного приведення), оскільки ви не можете безпосередньо викликати посилання на метод заперечення (спочатку потрібно зробити висновок типу).
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));