Java 8: проверка общих элементов в двух списках с помощью потоков

Я ищу статус, чтобы проверить, есть ли совпадение в двух списках пользователей в соответствии с именем пользователя.

List<User> a;
List<User> b;
for (User user : a) {
    for (User newUser : b) {
        if (user.getName().equals(newUser.getName())) {
        }
    }
}

Как я могу написать это на Java 8? Что-то вроде этого:

List<User> intersect = a.stream()
                    .filter(User::getName)
                    .collect(Collectors.toList());
как избежать npe с помощью java8
ΦXocę 웃 Пepeúpa ツ 02.09.2020 12:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
2 763
3

Ответы 3

Вы можете сделать что-то вроде ниже:

List<User> intersect = a.stream()
                     .filter(b::contains)
                     .collect(Collectors.toList());

Вам необходимо переопределить методы equals и hashCode в User. Для оптимизации вы можете сначала преобразовать b в HashSet.

Я не могу переоценить какой-либо метод в классе User!

Ahmad Al-Khazraji 24.10.2018 13:37

Один из способов сделать это с помощью Stream.anyMatch (это будет break в if) может быть:

a.stream().filter(user -> b.stream().anyMatch(newUser -> user.getName().equals(newUser.getName())))
          .map(User::getName)
          .forEach(System.out::println); // logic inside 'if' here (print for e.g.)

Если вы хотите повторить цикл (логика if) для всех таких совпадений:

a.forEach(user -> b.stream()
                   .filter(newUser -> user.getName().equals(newUser.getName()))
                   .map(newUser -> user.getName())
                   .forEach(System.out::println));

Вы можете сохранить один вызов user.getName() для каждого пользователя, просто выполнив map(User::getName)первый.

Holger 24.10.2018 14:50

Когда пользователь правильно определен с помощью hashCode и equals (в противном случае вы можете попробовать TreeSet вместо HashSet), выполните операции установки:

Set<User> common = new HashSet<>(a);
common.retainAll(b);

Если User.getName не используется для равенства:

Set<User> common = new TreeSet<>(Comparator.comparing(User::getName));
common.addAll(a);
common.retainAll(b);

Два вложенных цикла for в списках (также как потоки) будут иметь сложность O (N²), тогда как это O (N.log N).

retainAll возвращает boolean
Venkata Raju 24.10.2018 11:52

Будет ли это автоматически вызывать getName?

Ahmad Al-Khazraji 24.10.2018 13:35

@ AhmadAl-Khazraji, ты попал в самое слабое место; Благодарю. Добавлен компаратор. Если два разных пользователя могут иметь одно и то же имя, было бы разумнее возвращать Set<String> имен. Тогда подходило бы решение Stream с отображением.

Joop Eggen 24.10.2018 13:45

@ AhmadAl-Khazraji new TreeSet<>(a, Comparator.comparing(User::getName)) должен содержать только пользователей без повторяющихся имен.

Joop Eggen 24.10.2018 14:01

@JoopEggen в Java 8 такого конструктора нет. Стоит ли импортировать определенную библиотеку?

Ahmad Al-Khazraji 24.10.2018 15:38

@ AhmadAl-Khazraji моя ошибка, нужно 2 звонка. Поправил, извините, сегодня не стоило играть на StackOverflow.

Joop Eggen 24.10.2018 15:42

Другие вопросы по теме