一、前言
最近在做一個項目,獲取JDK8 Stream對象後,想要批量消費,不想自己寫個集合來做批量處理。而反應式編程實現比如rxjava或者reactor是有豐富的流操作符,所以調研了下如何把JDK8 Stream轉換爲反應式流。
二、批量消費
有時候場景需要我們批量消費以便提高執行效率,比如對應同一個表的插入操作,批量插入的效率比單條逐個插入效率要好很多。那麼對應給定的一個數據源,如何聚合數據爲批量那?當數據源是一個內存list時候,最簡單方法如下:
public static void main(String[] args) {
// 模擬數據, 創建list
List<Integer> personList = new ArrayList<>();
for (int i = 0; i < 98; ++i) {
personList.add(i);
}
// 切分處理
List<List<Integer>> list = Lists.partition(personList, 20);
list.stream().forEach(
tempList -> System.out.println(JSON.toJSONString(tempList))
);
}
使用Google guava包裏面的Lists.partition函數把list切分爲一個個最多包含20個元素的list列表,並打印輸出。
如果我們想要的是從這些流中每次讀取limit條記錄,然後批量處理這limit條記錄,這樣內存中每次只會存在limit條記錄。這時由於JDK Stream不支持Buffer操作,我們需要自己實現,實現代碼大概如下:
public static void main(String[] args) {
// 模擬數據, 創建list
List<Integer> personList = new ArrayList<>();
for (int i = 0; i < 98; ++i) {
personList.add(i);
}
// 緩存列表
List<Integer> mergeList = new ArrayList<>();
int limit = 20;
// 循環獲取元素並緩存
personList.stream().forEach(e -> {
if (mergeList.size() >= limit) {
System.out.println(JSON.toJSONString(mergeList));
mergeList.clear();
}
mergeList.add(e);
});
// 退出後,補漏處理
if (mergeList.size() > 0) {
System.out.println(JSON.toJSONString(mergeList));
}
}
如上代碼在Stream中迭代元素時,我們把元素緩存到mergeList列表,每當mergeList有了20個元素,則處理一次。最後等流結束後,如果mergeList還有元素則需要補漏處理下。
如果不想實現上面繁瑣代碼,我們可以考慮吧JDK8 Stream切換到反應式實現框架比如Reactor或者Rxjava,因爲後者有豐富的流操作符。其中Reactor的一個實現是:
public static void main(String[] args) {
// 模擬數據, 創建list
List<Integer> personList = new ArrayList<>();
for (int i = 0; i < 98; ++i) {
personList.add(i);
}
// 爲了使用buffer功能,轉換爲Reactor的流對象Flux
Flux flux = Flux.fromStream(personList.stream());
// 聚合消費
flux.buffer(20).subscribe(e -> System.out.println(JSON.toJSONString(e)));
}
如上代碼,我們使用Reactor框架的Flux.fromStream方法把JDKStream轉換爲Flux流對象,然後調用其buffer方法設置緩存20個元素消費一次,然後調用subscribe訂閱緩存流,並打印。