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