Потоки Java 34. Сбор 10. Collectors.groupingByConcurrent()

Терминальная операция либо возвращает одно значение (того же или другого типа, чем тип ввода), либо вообще ничего не возвращает (производит только побочные эффекты). Это не позволяет применить другую операцию после этого и закрывает поток.

В этом посте мы продолжим рассказывать о последней операции терминала, называемой collect():

R collect(Коллектор‹T,A,R› коллектор)

Это специализация операции reduce(). Он позволяет реализовать широкий спектр алгоритмов, используя готовые сборщики из класса java.util.stream.Collectors. Мы обсуждали, как создать собственный сборщик, в разделе Java streams 25. Сбор 1. Пользовательский сборщик. В этой статье мы будем использовать только сборщики, созданные классом Collectors.

Создание объекта Map с помощью коллектора Collectors.groupingByConcurrent()

Сборщик Collectors.groupingByConcurrent() дает практически тот же результат, что и сборщик Collectors.groupingBy() (см. Потоки Java 33. Сбор 9. Сборщик Collectors.groupingBy() ), за исключением того, что результирующая Map неупорядочена и оптимизирована для параллельной потоковой обработки.

Существует несколько перегруженных версий фабричных методов, создающих сборщик Collectors.c() (очень похожих на фабрики Collectors.groupingBy()):

Collector‹T,?,Map‹K,List‹T››› groupingByConcurrent(Function‹T,K› classifier) — возвращает Collector, реализующий операцию «группировать по» для входных элементов типа T, группировка элементов в соответствии с функцией классификации и возврат результатов в карту;

Коллектор‹T,?,Map‹K,D›› groupingByConcurrent(Функция‹T,K›классификатор, Collector‹T,A,D› ниже по течению) — возвращает Collector, реализующий каскадную «группу by» операция над входными элементами типа T, группировка элементов в соответствии с функцией классификации, а затем выполнение операции сокращения над значениями, связанными с данным ключом, с использованием указанного нисходящего коллектора;

Collector‹T,?,M› groupingByConcurrent(Function‹T,K›classifier, Supplier‹M› mapSupplier, Collector‹T,A,D› нижестоящий) — возвращает Collector, реализующий каскадную « group by» над входными элементами типа T, группируя элементы в соответствии с функцией классификации, а затем выполняя операцию сокращения над значениями, связанными с данным ключом, с использованием указанного нисходящего коллектора.

Функция классификатор извлекает из элемента значение, которое будет служить ключом в результирующей карте. Этот ключ сопоставляется со значением (по умолчанию List, но может быть любым другим объектом, созданным функцией нисходящей), которое содержит элементы потока, которые дали тот же ключ.

Нижестоящий – это сборщик, который создает объект (сопоставленный с ключом, созданным классификатором), в котором хранятся все элементы, давшие одно и то же значение ключа.

mapSupplier используется, когда требуется конкретная реализация интерфейса Map. Он вызывается только один раз (независимо от того, является ли поток параллельным или нет), в то время как сборщик, созданный с помощью Collectors.groupingBy(), вызывает соответствующий поставщик много раз).

Ниже приведены примеры использования Collectors.groupingByConcurrent():

  ConcurrentMap<String, List<String>> map1 = 
                 Stream.of("cat", "fish", "cat", "dog")
      .collect(Collectors.
            groupingByConcurrent(Function.identity()));
  System.out.print(map1);        
      //prints: {fish=[fish], cat=[cat, cat], dog=[dog]}
  ConcurrentMap<Integer, List<String>> map2 = 
                 Stream.of("cat", "fish", "cat", "dog")
      .collect(Collectors.
                 groupingByConcurrent(String::length));
  System.out.print(map2);    
                //prints: {3=[cat, cat, dog], 4=[fish]}
  ConcurrentMap<Integer, Set<String>> map3 = 
                   Stream.of("cat", "fish", "cat", "dog")
      .collect(Collectors.
                groupingByConcurrent(String::length, 
                                    Collectors.toSet()));
  System.out.print(map3);   
                       //prints: {3=[cat, dog], 4=[fish]}
  ConcurrentMap<String, Long> map4 = 
                   Stream.of("cat", "fish", "cat", "dog")
      .collect(Collectors.
          groupingByConcurrent(Function.identity(), 
                                 Collectors.counting()));
  System.out.print(map4);    
                       //prints: {fish=1, cat=2, dog=1}
  ConcurrentMap<Integer, Map<String, List<String>>> map5 = 
                      Stream.of("cat", "fish", "cat", "dog")
       .collect(Collectors.
               groupingByConcurrent(String::length, 
              Collectors.groupingBy(Function.identity())));
  System.out.print(map5);        
    //prints: {3={cat=[cat, cat], dog=[dog]}, 4={fish=[fish]}}
  ConcurrentMap<Integer, Map<String, Long>> map6 = 
                 Stream.of("cat", "fish", "cat", "dog")
        .collect(Collectors.
               groupingByConcurrent(String::length,
             Collectors.groupingBy(Function.identity(), 
                                 Collectors.counting())));
  System.out.print(map6);  
                  //prints: {3={cat=2, dog=1}, 4={fish=1}}
  ConcurrentSkipListMap<Integer, Map<String, Long>> map7 = 
                     Stream.of("cat", "fish", "cat", "dog")
        .collect(Collectors.            
                 groupingByConcurrent(String::length, 
                             ConcurrentSkipListMap::new,
                Collectors.groupingBy(Function.identity(), 
                                   Collectors.counting())));
  System.out.print(map7);    
                    //prints: {3={cat=2, dog=1}, 4={fish=1}}

В следующем посте мы поговорим о создании объекта Map с помощью коллектора Collectors.partitioningBy().

Смотрите другие сообщения о потоках Java 8 и сообщения на другие темы.
Вы также можете использовать страницы навигации для блогов, связанных с потоками Java:
Заголовки блогов потоков Java 8
> — Создать поток
Потоковые операции
Потоковая операция collect()
Исходный код всех примеров кода находится здесь, на GitHub.