Использование двойного двоеточия для метода ссылки на объект Java 8

У меня есть 2 List<xxx>, и мне нужно пересечь их по xxx.getId(), поэтому я использую Stream и Lambda. Вот эти шаги:

List<xxx> list1 = function1();
List<xxx> list2 = function2();
List<String> list1InString = list1.stream().map(input -> input.getId()).collect(toList());
list2 = list2.stream().filter(input -> list1InString.contains(input.getId())).collect(toList());

Я хочу сделать это, используя double colon, например:

list2 = list2.stream().filter(list1InString::contains).collect(toList());

Но это неверно, потому что contains ссылка на объект xxx не является методом String getId(). Я знаю, что трачу время на преобразование list1 в list1InString, но я не знаю лучшего метода. Любая помощь очень ценна, большое спасибо.

Редактировать: спасибо за многие ответы, я просто хочу сделать код более простым, используя двойное двоеточие (что для меня ново), но в этом случае его нельзя использовать. Особая благодарность Наману и Хольгеру за разъяснение моей проблемы.


person mmo2112    schedule 11.12.2019    source источник
comment
Использование ссылки на метод возможно только в том случае, если list2 является String или map перед fiiler, что, похоже, не так.   -  person Naman    schedule 11.12.2019
comment
@Naman, спасибо за ответ. Итак, мой шаг является необязательным ответом для моего случая - в этом случае нельзя использовать двойное двоеточие?   -  person mmo2112    schedule 11.12.2019
comment
Что ж, есть способ, предложенный Равиндрой в ответе, путем переопределения equals, но я бы не рекомендовал его лично из-за потери другой информации при сравнении объектов в целом. Другим было бы абстрагирование кода для фильтрации в служебный метод и использование его со ссылкой. Но этого не требуется, учитывая, что лямбда уже читается чисто и работает здесь надлежащим образом.   -  person Naman    schedule 11.12.2019
comment
Я предлагаю прочитать этот ответ на «Состав ссылки на метод». Речь идет об объединении двух экземпляров Function, но то же самое относится и к объединению Predicate и Function; вы можете комбинировать две ссылки на методы через вспомогательную функцию, но, в конце концов, нет никакого преимущества перед простым написанием лямбда-выражения.   -  person Holger    schedule 11.12.2019


Ответы (2)


Вы можете использовать альтернативный подход, как показано ниже:

List<XXX> items = list2.stream()
            .map(itemL1->{
                        return list1.stream().
                            filter((itemL2)->itemL2.getId().equals(itemL1.getId()))
                            .collect(Collectors.toList());
                    }
                )
            .flatMap(List::stream)
            .collect(Collectors.toList());
person Shrirang Kumbhar    schedule 11.12.2019
comment
Я думаю, что в моем случае нельзя назвать простое двойное двоеточие из-за разницы между строкой и объектом. Я закрою свой вопрос, спасибо за помощь. - person mmo2112; 11.12.2019
comment
Вместо сопоставления с List, за которым следует .flatMap(List::stream), вы можете использовать flatMap в первую очередь, то есть .flatMap(itemL1 -> list1.stream() .filter(itemL2 -> itemL2.getId().equals(itemL1.getId()))). Но в любом случае ни один из них не эквивалентен операции OP, которая скорее list2.stream() .filter(a -> list1.stream().anyMatch(b -> a.getId().equals(b.getId())) .collect(Collectors.toList());. Но предпочтительнее сначала собрать в коллекцию идентификаторы list1, особенно при использовании Set вместо List. - person Holger; 12.12.2019

Вы можете использовать немного другой подход:

List<xxx> list1 = function1();
List<xxx> list2 = function2();
Set<String> seen = new HashSet<>();

В союз:

Predicate<xxx> distinctFilter = x -> seen.add(x.getId());
result = Stream.concat(list1.stream(), list2.stream())
.filter(distinctFilter)
.collect(toList());

Чтобы пересечься:

Predicate<xxx> distinctFilter = x -> !seen.add(x.getId());
result = Stream.concat(list1.stream(), list2.stream())
.filter(distinctFilter)
.collect(toList());
person Mạnh Quyết Nguyễn    schedule 11.12.2019
comment
Спасибо за ваш ответ, но это не мой обязательный ответ. Мне нужно пересечь список 2, а не объединение. Мои первые шаги с использованием лямбда уже сделали это. - person mmo2112; 11.12.2019
comment
@ mmo2112 для объединения, вам просто нужно отрицать предикат. Смотрите обновленные - person Mạnh Quyết Nguyễn; 11.12.2019