JDK8之lambda处理stream的常用例子

前言

在日常的编码中,我们经常要对集合类对象进行处理。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会有更高的价值。所以想着,如果直接把代码丢上来,然后把文章要解释的内容以注释的形式填充到代码里,那是不是看完这段代码就能一次性的接受了内容和实践效果?之后的文章也可以继续这样试一试。

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