«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.