«1. Обзор

В этом уроке мы узнаем, как получить пересечение двух списков.

Как и многое другое, это стало намного проще благодаря введению потоков в Java 8.

2. Пересечение двух списков строк

Создадим два списка строк с некоторым пересечением — оба наличие дублирующихся элементов:

List<String> list = Arrays.asList("red", "blue", "blue", "green", "red");
List<String> otherList = Arrays.asList("red", "green", "green", "yellow");

А теперь определим пересечение списков с помощью потоковых методов:

Set<String> result = list.stream()
  .distinct()
  .filter(otherList::contains)
  .collect(Collectors.toSet());

Set<String> commonElements = new HashSet(Arrays.asList("red", "green"));

Assert.assertEquals(commonElements, result);

Сначала удаляем дублирующиеся элементы с отличными. Затем мы используем фильтр для выбора элементов, которые также содержатся в otherList.

Наконец, мы преобразуем наш вывод с помощью Collector. Пересечение должно содержать каждый общий элемент только один раз. Порядок не должен иметь значения, поэтому toSet — самый простой выбор, но мы также можем использовать toList или другой метод сбора.

Дополнительные сведения см. в нашем руководстве по коллекторам Java 8.

3. Пересечение списков пользовательских классов

Что, если наши списки содержат не строки, а экземпляры созданного нами пользовательского класса? Ну, пока мы следуем соглашениям Java, решение с потоковыми методами будет прекрасно работать для нашего пользовательского класса.

Как метод contains решает, появляется ли конкретный объект в списке? На основе метода равных. Таким образом, мы должны переопределить метод equals и убедиться, что он сравнивает два объекта на основе значений соответствующих свойств.

Например, два прямоугольника равны, если их ширина и высота равны.

Если мы не переопределяем метод equals, наш класс использует реализацию equals родительского класса. В конце дня, вернее, в цепочке наследования выполняется метод equals класса Object. Тогда два экземпляра равны, только если они ссылаются на один и тот же объект в куче.

Для получения дополнительной информации о методе equals см. нашу статью о контрактах Java equals() и hashCode().

4. Заключение

В этой быстрой статье мы увидели, как использовать потоки для вычисления пересечения двух списков. Есть много других операций, которые раньше были довольно утомительными, но довольно простыми, если мы знаем, как работать с Java Stream API. Ознакомьтесь с нашими дальнейшими руководствами по потокам Java здесь.

Примеры кода доступны на GitHub.