jdk8 streamAPI 中Collector收集器Collectors.groupingBy分組難點精解

collector

collector的簡單場景,一般是在流處理完畢,想要收集對象的收尾工作。代碼如下。

List<String> list = Stream.of("kimmy", "robin", "lisa", "lulu", "mike", "jimmy")
                .collect(Collectors.toList());

這個收集器主要是把 流水線上的每一個小部件進行收集,並進行裝箱。那麼這個操作由
大名鼎鼎的Collector來操作。

精解

在這裏插入圖片描述

示例代碼

List<String> list = Stream.of("kimmy", "robin", "lisa", "lulu", "mike", "jimmy")
    .parallel().collect(new Collector<String, List<String>, List<String>>() {
         @Override
           public Supplier<List<String>> supplier() {
               return ()->new ArrayList<String>();
           }
           @Override
           public BiConsumer<List<String>, String> accumulator() {
               return (list,item)->list.add(item);
           }
           @Override
           public BinaryOperator<List<String>> combiner() {
               return (list1,list2)->{list1.addAll(list2);return list1;};
           }
           @Override
           public Function<List<String>, List<String>> finisher() {
               return (list)->{return list;};
           }
           @Override
           public Set<Characteristics> characteristics() {
               return Set.of();
           }
       });

從最簡單的層次看這些代碼,supplier是容器的提供者,每一次需要臨時容器的存儲都是需要在這裏構造容器的。accumulator是累加器,每一次,我們的流水線的數據將會通過該函數裝入到supplier提供的容器,combiner,如果聲明瞭parallel()併發操作,那麼數據在一開始會被拆開成爲n條流水線,那麼每條流水線都會調用一次supplier產生一個臨時容器,再通過accumulator裝着每一條流水線的數據,最後,纔到combiner登場,combiner在不是併發的情況下是無用的。最後是finisher,該函數主要是用做中間容器與最後返回結果集的整合的操作。

最後,你可能會發現筆者漏了一個方法沒有講,characteristics(),這個方法是返回一個Set集合,裏面裝的是枚舉值,這個方法可見是用於收集器的一些其他的配置,首先就最簡單的講,如果返回的是如下,那麼finisher函數將不再執行,程序將認爲中間對象就是返回的結果對象,這要求泛型
在這裏插入圖片描述
必須保持一致。否則會發生錯誤。

@Override
public Set<Characteristics> characteristics() {
    return Set.of(Characteristics.IDENTITY_FINISH);
}

另外的2個參數時相互一起配合使用的。官方的解釋是accumulator會被併發的調用,但是實際測試還是需要parallel()配合使用,一般配置UNORDERED,使得流水線上的數據以亂序方式處理。

@Override
public Set<Characteristics> characteristics() {
   return Set.of(Characteristics.CONCURRENT,Characteristics.UNORDERED);
}

那麼返回的結果集當然也是亂序的了。
before:
“kimmy”, “robin”, “lisa”, “lulu”, “mike”, “jimmy”,“kimmy”, “robin”, “lisa”, “lulu”, “mike”, “jimmy”

After;
[robin, lisa, kimmy, robin, lisa, kimmy, jimmy, mike, lulu, jimmy, lulu, mike]

有的同學不知道parallel是什麼,在這裏我簡單的描述一下:就是在stream 的時候,調用一下paralle方法。

 Stream.of("kimmy", "robin", "lisa", "lulu", "mike", "jimmy","kimmy", "robin", "lisa", "lulu", "mike", "jimmy")
                .parallel().collect(...))

注意

在這裏插入圖片描述
那麼既然int 類型無法使用,就應該使用mapToObj轉化成爲字符串對象。

Collectors.groupingBy

假設我們有一個以數字1,10組成的流,需要將該流按照奇數偶數進行分組,那麼此時就需要使用groupBy了,groupBy函數一共有2個處理步驟,分別爲分組,收集,其中分組操作是不可忽略的,而收集操作是可以忽略的。

Map<String, List<Integer>> collect = IntStream.range(1, 10).mapToObj(it -> Integer.valueOf(it)).collect(Collectors.groupingBy(new Function<Integer, String>() {
   @Override
    public String apply(Integer integer) {
        if (integer % 2 == 0) {
            return "even";
        } else {
            return "odd";
        }
    }
}));
System.out.println(collect);
//返回的結果
//{even=[2, 4, 6, 8], odd=[1, 3, 5, 7, 9]}

如果希望在子流,即分組流在進行操作。可以在參數2,3進行定製

流程以及接口詳細介紹

在這裏插入圖片描述在這裏插入圖片描述

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章