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進行定製