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 .