Перейти к основному содержимому

Новые сборщики потоков в Java 9

· 3 мин. чтения

1. Обзор

В Java 8 были добавлены коллекторы , которые помогали накапливать входные элементы в изменяемые контейнеры, такие как Map , List и Set .

В этой статье мы рассмотрим два новых сборщика, добавленных в Java 9: Collectors.filtering и Collectors.flatMapping , которые используются в сочетании с Collectors.grouping , предоставляя интеллектуальные коллекции элементов.

2. Фильтрующий коллектор

Collectors.filtering похож на Stream filter() ; он используется для фильтрации элементов ввода, но используется для разных сценариев. Фильтр Stream используется в цепочке потоков, тогда как фильтрация это Collector , который был разработан для использования вместе с groupingBy . ``

С фильтром Stream значения сначала фильтруются, а затем группируются. Таким образом, отфильтрованные значения исчезают, и от них не остается и следа. Если нам нужна трассировка, нам нужно сначала сгруппировать, а затем применить фильтрацию, что на самом деле делает Collectors.filtering .

Collectors.filtering принимает функцию для фильтрации входных элементов и коллектор для сбора отфильтрованных элементов :

@Test
public void givenList_whenSatifyPredicate_thenMapValueWithOccurences() {
List<Integer> numbers = List.of(1, 2, 3, 5, 5);

Map<Integer, Long> result = numbers.stream()
.filter(val -> val > 3)
.collect(Collectors.groupingBy(i -> i, Collectors.counting()));

assertEquals(1, result.size());

result = numbers.stream()
.collect(Collectors.groupingBy(i -> i,
Collectors.filtering(val -> val > 3, Collectors.counting())));

assertEquals(4, result.size());
}

3. Сборщик FlatMapping

Collectors.flatMapping похож на Collectors.mapping , но имеет более детальную цель . Оба сборщика принимают функцию и сборщик, в котором собираются элементы, но функция flatMapping принимает поток элементов, который затем накапливается сборщиком.

Давайте посмотрим на следующий класс модели:

class Blog {
private String authorName;
private List<String> comments;

// constructor and getters
}

Collectors.flatMapping позволяет нам пропустить промежуточную коллекцию и писать напрямую в один контейнер, который сопоставляется с группой, определенной Collectors.groupingBy :

@Test
public void givenListOfBlogs_whenAuthorName_thenMapAuthorWithComments() {
Blog blog1 = new Blog("1", "Nice", "Very Nice");
Blog blog2 = new Blog("2", "Disappointing", "Ok", "Could be better");
List<Blog> blogs = List.of(blog1, blog2);

Map<String, List<List<String>>> authorComments1 = blogs.stream()
.collect(Collectors.groupingBy(Blog::getAuthorName,
Collectors.mapping(Blog::getComments, Collectors.toList())));

assertEquals(2, authorComments1.size());
assertEquals(2, authorComments1.get("1").get(0).size());
assertEquals(3, authorComments1.get("2").get(0).size());

Map<String, List<String>> authorComments2 = blogs.stream()
.collect(Collectors.groupingBy(Blog::getAuthorName,
Collectors.flatMapping(blog -> blog.getComments().stream(),
Collectors.toList())));

assertEquals(2, authorComments2.size());
assertEquals(2, authorComments2.get("1").size());
assertEquals(3, authorComments2.get("2").size());
}

Collectors.mapping сопоставляет все сгруппированные авторские комментарии с контейнером сборщика, т.е. List , тогда как эта промежуточная коллекция удаляется с помощью flatMapping , поскольку она дает прямой поток списка комментариев для сопоставления с контейнером сборщика.

4. Вывод

В этой статье показано использование новых коллекторов , представленных в Java9, т . е. Collectors.filtering() и Collectors.flatMapping() в сочетании с Collectors.groupingBy() .

Эти коллекторы также можно использовать вместе с Collectors.partitioningBy() , но он создает только два раздела в зависимости от условий, а реальная мощь коллекторов не используется; поэтому исключено из этого руководства.

Полный исходный код для фрагментов кода в этом руководстве доступен на GitHub .