博客 / 詳情

返回

Stream流處理快速上手最佳實踐 | 京東物流技術團隊

一 引言

JAVA1.8得益於Lambda所帶來的函數式編程,引入了一個全新的Stream流概念Stream流式思想類似於工廠車間的“生產流水線”,Stream流不是一種數據結構,不保存數據,而是對數據進行加工處理。Stream可以看作是流水線上的一個工序。在流水線上,通過多個工序讓一個原材料加工成一個商品。

二 常用方法介紹

2.1 獲取Stream流

所有的 Collection 集合都可以通過 stream 默認方法獲取流;

java.util.Collection 接口中加入了default方法 stream 用來獲取流,所以其所有實現類均可獲取流。

ArrayList<XyBug> xyBugList = new ArrayList();
Stream<XyBug> stream = xyBugList.stream();


Stream 接口的靜態方法 of 可以獲取數組對應的流。

//String
Stream<String> stream = Stream.of("aa", "bb", "cc");
//數組
String[] arr = {"aa", "bb", "cc"};
Stream<String> stream7 = Stream.of(arr);
Integer[] arr2 = {11, 22, 33};
Stream<Integer> stream8 = Stream.of(arr2);
//對象
XyBug xyBug1 = new XyBug();
XyBug xyBug2 = new XyBug();
XyBug xyBug3 = new XyBug();
Stream<XyBug> bugStream = Stream.of(xyBug1, xyBug2, xyBug3);



2.2 Stream 數據處理常用方法

forEach方法

該方法接收一個 Consumer 接口函數,會將每一個流元素交給該函數進行處理

List<String> list = new ArrayList<>();
Collections.addAll(list, "str1", "str2", "str3", "str4", "str5", "str6");
list.stream().forEach((String s) -> {
  System.out.println(s);
  });
//簡寫
list.stream().forEach(s -> System.out.println(s));


s代表list中的每一個元素,流式處理依次遍歷每個元素

->後的代碼為每個元素處理邏輯

count方法

count 方法來統計其中的元素個數,返回值為long類型

long count = list.stream().count();


distinct方法

對流中的數據進行去重操作,普通類型可直接去重

//將22、33重複數據去除
Stream.of(22, 33, 22, 11, 33).distinct().collect(Collectors.toList());


自定義類型是根據對象的hashCode和equals來去除重複元素的

XyBug實體類中加@Data註解,hashCode和equals會別重寫,在使用distinct方法時判斷去重

ArrayList bugList = JSON.parseObject(bugs, ArrayList.class);
ArrayList<XyBug> xyBugList = new ArrayList();
List collect = (List) bugList.stream().distinct().collect(Collectors.toList());


通過distinct()方法去重,去重後的數據通過collect(Collectors.toList())組成新6的list

limit方法

方法可以對流進行截取,只取用前n個,參數是一個long型,如果集合當前長度大於參數則進行截取。否則不進行操作

List<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4", "5", "6");
List<String> collect = list.stream().limit(3).collect(Collectors.toList());


將前3個String對象截取,組成新的list

skip方法

如果希望跳過前幾個元素,可以使用 skip 方法獲取一個截取之後的新流,如果流的當前長度大於n,則跳過前n個;否則將會得到一個長度為0的空流

List<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4", "5", "6");
List<String> collect = list.stream().skip(3).collect(Collectors.toList());


跳過前3個String對象,後三個組成新的list

filter方法

filter用於過濾數據,返回符合過濾條件的數據,可以通過 filter 方法將一個流轉換成另一個子集流,該接口接收一個 Predicate 函數式接口參數(可以是一個Lambda或方法引用)作為篩選條件

List<String> list = new ArrayList<>();
Collections.addAll(list, "1", "22", "3", "4", "55", "6");
//filter方法中寫入篩選條件,將過濾後的數據組成新的list
list.stream().filter(s -> s.length() == 2).collect(Collectors.toList());


通過該條語句s -> s.length() == 2,篩選出22、55

map方法

將流中的元素映射到另一個流中,可以將當前流中的T類型數據轉換為另一種R類型的流

List<PersonCrDto> laputaCrDtos = queryListLaputaByBeginEndTime(begin, end);
//將list中的PersonCrDto對象的userName屬性取到,收集成set集合
laputaCrDtos.stream().map(PersonCrDto::getUserName).collect(Collectors.toSet())


將list中的每個對象的userName數據拿到,組成Set集合

stream分組
List<XyBug> list = new ArrayList<>();
Map<String, List<XyBug>> collect = list.stream().collect(Collectors.groupingBy(XyBug::getBugType));


根據bug類型進行分組,分組後會組成map,key是組名,value是組下的數據

stream排序

sort(),默認正序排列,加入reversed()方法後倒敍排列

List<XyBug> list = new ArrayList<>();
//根據createTime正序排列
List<XyBug> collect = list.stream().sorted(Comparator.comparing(XyBug::getCreateTime)).collect(Collectors.toList());
//根據createTime倒敍排列
List<XyBug> collect = list.stream().sorted(Comparator.comparing(XyBug::getCreateTime).reversed()).collect(Collectors.toList());



collect方法

將處理後數據收集為list,collect(Collectors.toList())

將處理後數據收集為set,collect(Collectors.toSet())

根據某個字段值將數據分組map,collect(Collectors.groupingBy(o -> o.value())))

三 實踐舉例

需求:將bug數據通過orgTierName分組,存儲到map中

未使用Stream,需要使用for循環並且進行各種判斷,代碼行數較多

HashMap<String, List<XyBug>> map = new HashMap<>();
for (XyBug one : bugList){
    if(one.getOrgTierName() != null){
        if(map.get(one.getOrgTierName()) == null){
            List<XyBug> list = new ArrayList();
            list.add(one);
            map.put(one.getOrgTierName(),list);
        }else {
            map.get(one.getOrgTierName()).add(one);
        }
    }
}


使用Stream,一行代碼搞定,直觀並高效

collectDeptBugMap = bugList.stream().filter(o -> o.getOrgTierName() != null).collect(Collectors.groupingBy(o -> o.getOrgTierName()));


四 總結

Stream是對集合(Collection)對象功能的增強,能對集合對象進行各種非常便利、高效的聚合操作,或者大批量數據操作,提高編程效率、簡潔性和程序可讀性。本文通過簡單舉例,希望幫助讀者快速上手使用流處理,Stream流處理功能非常強全,更多方法請參考API文檔。

作者:京東物流 楊靖平

來源:京東雲開發者社區  自猿其説Tech 轉載請註明來源

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.