前言
在日常的編碼中,我們經常要對集合類對象進行處理。JDK8之前,我們可能要用for循環等方式來處理集合中的每一個元素。不過JDK8的lambda表達式給了我們更方便的選擇。
關於lambda表達式和stream的介紹,這裏有一篇文章寫得非常好,詳細易懂。JDK 8 函數式編程入門
直接上demo
既然本文是要寫一些常用的例子,那就直接上demo了。
1.先創建一個簡單的實體類
@Data
@Builder
public class DefaultTestBean {
private int id;
private String name;
private String area;
private double score;
}
2.初始化一個我們要處理的list
private List<DefaultTestBean> initList() {
List<DefaultTestBean> resultList = Lists.newArrayList();
resultList.add(DefaultTestBean.builder().id(1).name("小白").area("A").score(10.1).build());
resultList.add(DefaultTestBean.builder().id(2).name("小紅").area("B").score(9.6).build());
resultList.add(DefaultTestBean.builder().id(3).name("小黃").area("A").score(5.9).build());
resultList.add(DefaultTestBean.builder().id(4).name("小藍").area("C").score(3.3).build());
return resultList;
}
3.開始搞事情,看註釋就好
/**
* 盤他!
*/
public void showMeHowToUseStream() {
List<DefaultTestBean> list = initList();
PrintUtil.printJSONString("initList", list);
// 1.【轉list】提取list中對象的某個字段,返回list。用map進行類型轉換,用collect(Collectors.toList())返回新的list。
List<String> nameList = list.stream().map(DefaultTestBean::getName).collect(Collectors.toList());
PrintUtil.printJSONString("nameList", nameList);
// 2.【過濾】對某個字段過濾,用filter。只有符合filter中的bean纔會保留下來。
List<DefaultTestBean> highCoreList = list.stream().filter(bean -> bean.getScore() > 5.0).collect(Collectors.toList());
PrintUtil.printJSONString("highCoreList", highCoreList);
// 3.【排序】根據id這個字段返回倒序排序list。如果是a-b,則是升序。如果是b-a,則是倒序。
List<DefaultTestBean> sortList = list.stream().sorted((a, b) -> b.getId() - a.getId()).collect(Collectors.toList());
PrintUtil.printJSONString("sortList", sortList);
// 4.【轉map】list轉成map,key爲id,value爲bean。用Collectors.toMap轉成map。
Map<Integer, DefaultTestBean> idBeanMap = list.stream().collect(Collectors.toMap(DefaultTestBean::getId, bean -> bean));
PrintUtil.printJSONString("idBeanMap", idBeanMap);
// 5.【轉map】提取list中信息轉成map,key爲id,value爲name。同上。
Map<Integer, String> idNameMap = list.stream().collect(Collectors.toMap(DefaultTestBean::getId, DefaultTestBean::getName));
PrintUtil.printJSONString("idNameMap", idNameMap);
// 6.【轉map分組】對list中的bean進行分組,key爲area,value爲list。
Map<String, List<DefaultTestBean>> areaListMap = list.stream().collect(Collectors.groupingBy(DefaultTestBean::getArea));
PrintUtil.printJSONString("areaListMap", areaListMap);
}
public static <T> void printJSONString(String title, T t) {
System.out.println(title + ":" + JSON.toJSONString(t, SerializerFeature.IgnoreNonFieldGetter));
}
執行showMeHowToUseStream方法,我們可以看到以下輸出:
initList:[{"area":"A","id":1,"name":"小白","score":10.1},{"area":"B","id":2,"name":"小紅","score":9.6},{"area":"A","id":3,"name":"小黃","score":5.9},{"area":"C","id":4,"name":"小藍","score":3.3}]
nameList:["小白","小紅","小黃","小藍"]
highCoreList:[{"area":"A","id":1,"name":"小白","score":10.1},{"area":"B","id":2,"name":"小紅","score":9.6},{"area":"A","id":3,"name":"小黃","score":5.9}]
sortList:[{"area":"C","id":4,"name":"小藍","score":3.3},{"area":"A","id":3,"name":"小黃","score":5.9},{"area":"B","id":2,"name":"小紅","score":9.6},{"area":"A","id":1,"name":"小白","score":10.1}]
idBeanMap:{1:{"area":"A","id":1,"name":"小白","score":10.1},2:{"area":"B","id":2,"name":"小紅","score":9.6},3:{"area":"A","id":3,"name":"小黃","score":5.9},4:{"area":"C","id":4,"name":"小藍","score":3.3}}
idNameMap:{1:"小白",2:"小紅",3:"小黃",4:"小藍"}
areaListMap:{"A":[{"area":"A","id":1,"name":"小白","score":10.1},{"area":"A","id":3,"name":"小黃","score":5.9}],"B":[{"area":"B","id":2,"name":"小紅","score":9.6}],"C":[{"area":"C","id":4,"name":"小藍","score":3.3}]}
4.有些小坑
在轉map時,key值需要唯一,否則會報錯。
看demo:
public void trap() {
List<DefaultTestBean> list = initList();
// 1.轉map時,key值需要唯一。否則會報錯。
list.add(DefaultTestBean.builder().id(1).name("白小白").area("A").score(10.1).build());
// 有重複,報錯:java.lang.IllegalStateException: Duplicate key 小白
Map<Integer, String> idNameMap = list.stream().collect(Collectors.toMap(DefaultTestBean::getId, DefaultTestBean::getName));
PrintUtil.printJSONString("idNameMap", idNameMap);
// 我們可以用Collectors.toMap的重載方法,傳入一個合併函數來決定如何合併相同key的值即可。
// 我們默認返回list中第一個出現的重複的值
Map<Integer, String> idNameMap = list.stream().collect(Collectors.toMap(DefaultTestBean::getId, DefaultTestBean::getName, (value1, value2) -> value1));
PrintUtil.printJSONString("idNameMap", idNameMap);
// 我們把兩個值按照自己的邏輯合併到一起
Map<Integer, String> idMergeNameMap = list.stream().collect(Collectors.toMap(DefaultTestBean::getId, DefaultTestBean::getName, (value1, value2) -> value1 + "和" + value2));
PrintUtil.printJSONString("idMergeNameMap", idMergeNameMap);
}
}
總結
個人認爲,對於集合類的日常處理,差不多就是這幾種。如果以後發現還會經常用到其他的處理方式,會補充進來的。
其次,自己在想這種把內容直接寫到代碼註釋裏的方式,可讀性如何。因爲我感覺對於一些實用性的文章,還是要多上一些代碼和demo會有更高的價值。所以想着,如果直接把代碼丟上來,然後把文章要解釋的內容以註釋的形式填充到代碼裏,那是不是看完這段代碼就能一次性的接受了內容和實踐效果?之後的文章也可以繼續這樣試一試。