Stream流在实际业务场景的妙用

        在我们学习JDK8的过程中,有一个非常重要的知识点,那就是Stream流了,Stream流能取代频繁的for循环,提升了代码执行效率,而且内置了很多方法处理集合大大简化了处理集合的繁琐复杂步骤,但是方法比较多,学起来比较生硬;本文章以作者本人在工作中实际的业务场景来介绍stream流各个方法的使用,以下以业务场景为单元介绍点,结合各个stream流的方法简化以前繁杂的普通代码。

1、List<Map>里的某个属性值取出来拼成一串字符串

before :需要for循环一个一个把元素取出来用字符串拼接,拼接完后还需要去除最后一个拼接符,非常麻烦

for (int i = 0; i < mapList.size(); i++) {
    ids += mapList.get(i).get("id") + ",";
}
if (ids != null && ids .length() > 0) {
    ids = ids .substring(0, ids .length() - 1);
}

after :先用map取出属性值转成Stream<String> 然后用终结方法的joing()方法直接拼接

ids = mapList.stream()
    .map(item->item.get("id").toString())
    .collect(Collectors.joining(","));

(List<String> list 当然也可以用String.join(",", list)的方法直接拼接更快更简单,本篇主要以介绍Stream流的方法为主,故尽量使用Stream流的方法)

2、List<Map>需要取最大(小)的某个值

before :通过for循环把元素取出来和最大值maxScore比较,大于则取代新的最大值

Integer maxScore = 0;
for (Map item : mapList) {
    if (item.getInt("score") > max ) {
        max = item.getInt("score");
    }
}

after :先用map取出属性值转成Stream<Integer> 然后用reduce归纳方法获取到需要的数据

Integer maxScore = mapList.stream()
        .map(t -> t.getInt("score"))
        .reduce(0, (x, y) -> x > y ? x : y);

这里介绍一下reduce方法的使用:

如果需要将所有数据归纳得到一个数据,可以使用reduce方法。方法签名: 

//T identity : 默认值
// Binaryoperator<T> accumulator : 对数据进行处理的方式
reduce(T identity, Binaryoperator<T> accumulator ) ;

/**
reduce如何执行?
第一次,将默认值赋值给x,取出集合第一元素赋值给y 进行运算得出结果
第二次,将上一次返回的结果赋值x,取出集合第二元素赋值给y 进行运算得出结果
第三次,将上一次返回的结果赋值x,取出集合第三元素赋值给y 进行运算得出结果
 ...
*/
Integer reduce = Stream.of(4, 5, 6, 7).reduce(0, (x, y) -> {
    System.out.println("x=>" + x + " y=>" + y);
    return x + y;
});
System.out.println("reduce = " + reduce);
// 得到的结果是[4, 5, 6, 7]的总和

打印结果:

x=>0 y=>4
x=>4 y=>5
x=>9 y=>6
x=>15 y=>7
reduce = 22

 取最小、平均、求和这种将集合的数据归纳成一个数据时均可用reduce方法

 Integer sum = mapList.stream()
    .map(t -> t.getInt("score"))
    .reduce(0, Integer::sum);

3、JSONArray转成JSONObject的List形式使用Stream流

JSONArray orgList;
orgList.stream()
        .map(o ->{
            if ( o instanceof LinkedHashMap){
                return JSONObject.parseObject(JSON.toJSONString(o));
            }else{
                return (JSONObject)o;
            }
        }).forEach(item ->{
            // item已经是JSONObject,可以使用里面的方法了
            ...    
        });

4、两个List<Map>取交集,然后进行处理

假设有用户集合userList,和用户部门关联集合deptList,这里以用户集合userList作为主体,两集合之间有两种对应关系;一种是一对一,另一种是一对多(可理解成 一个用户只能有一个部门 / 一个用户可以有多个部门);两种情况处理方式类似,只是分组方式不同。

① 一对一

// Dept={"deptId":"","deptName":"",userId:""}
List<Dept> deptList;
// 以用户id作为key构建一个map value存的是对应的部门Dept
Map<String, Dept> userDeptMap= deptList
    .stream()
    .collect(Collectors.toMap(
            Dept::getUserId,
            Function.identity(),
            (x, y) -> x
    ));
// User={"userId":"",userName:""}
List<User> userList;
userList.stream().forEach(user->{
    if (userDeptMap.containsKey(id)){
        Dept dept = userDeptMap.get(id);
    }else{
        // 改用户不存在对应的部门
    }
});

通过将 集合deptList构建成Map<String,Dept>的形式,方便于主体集合userList取用,从而避免了循环中再次嵌套循环,优化了代码执行效率;

② 一对多

// Dept={"deptId":"","deptName":"",userId:""}
List<Dept> deptList;
// 以用户id作为key构建一个map value存的是对应的部门集合List<Dept>
Map<String, List<Dept>> userDeptMap= deptList
    .stream()
    .collect(Collectors.groupingBy(Dept::getUserId));
// User={"userId":"",userName:""}
List<User> userList;
userList.stream().forEach(user->{
    if (userDeptMap.containsKey(id)){
        List<Dept> deptList = userDeptMap.get(id);
    }else{
        // 改用户不存在对应的部门
    }
});

和①大体类似,唯一区别是①的分组方法是Collectors.toMap() ②的分组方法是Collectors.groupingBy()

5、用流来进行简单分页

当不方便在SQL查询做好分页时,此时就必须要在代码层来进行分页,可以使用limit和skip的结合使用达到分页效果

long pageNo = listQueryModel.getPageNum();
long pageSize = listQueryModel.getPageSize();
list = list.stream().skip((pageNo - 1) * pageSize).limit(pageSize).collect(Collectors.toList());

Stream流能大大简化代码的编写,使代码看起来简洁漂亮,唯一不足可能是可读性稍差点,这也只是对于不熟悉流的使用人而言,后续深度使用便不存在此问题,而且你会发现Stream流真的真的很好用!另外还有很多业务场景用到Stream流,想起来再慢慢更新吧!

--------------------------------  to be continue -------------------------------- 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值