Stream流的具体使用讲解

大四学生刚来公司实习,对于一些Java8的特性还不够了解,今天在业务上有一段代码能够帮助自己更好的了解stream流,在各种百度之后,简单谈一下关于stream的各类方法的具体使用。

相信看完本文,大家会对stream流的基本使用方法有一个基本的认识。

凭借个人理解所写,如有不足之处,希望大佬们斧正。

流的使用首先要搞懂lambda表达式

该表达式自Java8引入,简单来讲lambda表达式就是将一段代码赋值给一个变量,如此使用简洁优雅,该表达式所关注的只有两点,一是入参,二是执行逻辑

本文使用了大量的lambda表达式,该表达式箭头左右两侧分别是参数以及执行逻辑,理解本文对于stream流会有一个基本的了解。

该代码的使用场景在于将已经传入的一个dto实体类,实体类中有一个creatorName字段以及一个createdBy字段,接收的时候只有一个createdby字段我们要做的是根据Int类型的createdBy字段在系统数据库里查询相应的数据库里面有个User表User表的id与createdBy是一致的,所以可以根据user表的用户realName设置给creatorname。

关于该代码的上下文

@Override
    public Page<SoHeader23955> selectList(PageRequest pageRequest, SoHeaderDto dto) {
        Page<SoHeader23955> page = PageHelper.doPageAndSort(pageRequest, () -> soHeader23955Repository.selectList(Utils.transformObj(dto, SoHeader23955.class)));
        String userIds = page.getContent().stream().map(l -> l.getCreatedBy().toString()).collect(Collectors.toSet()).stream().collect(Collectors.joining(","));
        if (StringUtils.isNotEmpty(userIds)) {
            List<BaseUser> users = baseUserRepository.selectByIds(userIds);
            page.getContent().forEach(l -> {
                l.setCreatorName(users.stream().filter(u -> u.getId().equals(l.getCreatedBy())).findFirst().get().getRealName());
            });
        }
        return page;
    }

要讲解的关于流的代码

String userIds = page.getContent().stream().map(l -> l.getCreatedBy().toString()).collect(Collectors.toSet()).stream().collect(Collectors.joining(","));

最开始page.getContent方法是返回一个list集合(这是利用一个封装好的方法)

之后.stream().map()是将其转换成流的方式,map方法是取出当前流的某个元素,然后对其进行处理。本方法是从一种数据类型转换成新的数据类型,即你可以将一个集合的某一个字段给转换数值类型。在这里我们获得了需要处理的createdBy字段然后使用了toString方法转换成了String类型。在map里你可以对你的数据进行任意地处理然后获取返回值。

之后的 collect(Collectors.toSet())方法是将list集合转换成set集合,原因在于set集合无序且不允许重复,在这里简单给大家看一下三种集合的特点

 将转换好的集合再次设置为流(流每一次迭代完毕都会失效)之后使用 collect(Collectors.joining(","),该方法返回的是字符串 

 到此我们就完成了对一个list数组的某一个int类型字段的无重复化以及转换成String类型的处理。

之后我们就可以根据我们获取得到的id集合获取用户信息了

    List<BaseUser> users = baseUserRepository.selectByIds(userIds);
            page.getContent().forEach(l -> {
                l.setCreatorName(users.stream().filter(u -> u.getId().equals(l.getCreatedBy())).findFirst().get().getRealName());
                });

对这个集合的每个creatorname字段进行处理,首先使用遍历将每个类对象取出来,然后将user表里转换成流使用fliter进行筛选获取第一个值之后getname即可。

我刚开始学的时候对于fliter和foreach还有点懵,其实很简单fliter类似于一个工具一个漏斗将符合条件的字段筛选出来,foreach是对每个成员都进行处理

最后简单谈一下对于学习流的看法,对于新人来说,流的使用确实有点晦涩难懂,我觉得最好的学习方式就是要到实际场景上去尝试,尝试多了就会用了,用多了便很容易理解了,有的时候会用和理解与否并不矛盾。在实际开发中,单个的实体类往往很少用到,用的最多的还是list集合用法,流的使用可以极大地提高效率,还是很有必要去学习的

5.6补充 stream().map的使用

从数据库查询的⽤户集合
现在想获取User的⾝份证号码;在后续的逻辑处理中要⽤;
常⽤的⽅法我们⼤家都知道,⽤for循环,
List idcards=new ArrayList();//定义⼀个集合来装⾝份证号码
for(int i=0;i<users.size();i++){
idcards.add(users.get(i).getIdcard());
}
这种⽅法要写好⼏⾏代码,有没有简单点的,有,java8 API能⼀⾏搞定:
List idcards= users.stream().map(User::getIdcard).collect(Collectors.toList())
解释下⼀这⾏代码:
users:⼀个实体类的集合,类型为List
User:实体类
getIdcard:实体类中的get⽅法,为获取User的idcard

5.10补充

map和foreach的区别查看两者源码发现foreach没有返回值,但是map是有返回值的,因此map是对与集合中的某一个元素进行操作并且返回。

除此之外map集合家还有一个重要特点是map集合是需要和stream流连用的,但是foreach并不需要

void forEach(Consumer<? super T> action);

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

粘一段关于foreach使用的代码,可以看到foreach是用来为集合的某个字段设置值的。

   list.forEach(l-> {
            String code = codeRuleBuilder.generateCode("HZERO.37810.ORDER.NUMBER", null);
            l.setOrderNumber(code);

        });

关于map的方法

   // 定义一个 Integer 类型的集合
    List<Integer> ids = Arrays.asList( 1, 3, 9,  5);
// 获取对应的和
    ids.stream().map(a-> a+a).forEach(System.out::println);

关于将list结合转换成map,参数列表里面三个参数的问题。

     List<ResultModelLines> modelLines = this.selectByCondition(builder);
          Map<String, List<String>> tableCodeMap = modelLines.stream().collect(Collectors.toMap(ResultModelLines::getTableCode, item -> Lists.newArrayList(item.getFieldCode()), (a, b) -> {
                a.addAll(b);
                return a;
            }));

第一个参数:ResultModelLines::getTableCode表示选择Person的getId作为map的key值;

第二个参数:item -> Lists.newArrayList(item.getFieldCode())表示选择将原来的对象作为Map的value值

第三个参数:(a,b)->a中,如果a与b的key值相同,选择a作为那个key所对应的value值。

10/31

使用stream流进行多字段去重

到了实际的业务场景中,有的业务需求中,往往某条记录需要多个字段进行去重,这个时候我们就可以使用stream进行多个字段的筛选,在这里我使用了invoiceCode以及invoiceNo两个字段进行校验。

        List<UncertifiedInvoice> uncertifiedInvoices = uncertifiedInvoices1.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getInvoiceCode() + ";" + o.getInvoiceNo()))), ArrayList::new));

11.22更新

使用Stream按照某个字段进行排序

今天在开发中业务需要将我们在查询时,将某些导入的信息按照某个数值字段按照升序排序展示

经过排查后发现是插入时没有按照顺序来插入,因此我们需要再插入之前按照这个字段的数值排序

插入即可,同样的我们使用Stream一行搞定!

关键代码如下

            invoicingOrderHeaderList = invoicingOrderHeaderList.stream().sorted(Comparator.comparing(e -> e.getInvoiceSourceFlag())).collect(Collectors.toList());

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值