Java8 stream流操作(上)

本文是我在学习Java8的时候参考下面大佬的文章拷贝的,仅用于个人整理和学习用途
原文地址:https://www.jianshu.com/p/0bb4daf6c800
##一. 什么是 Stream

Stream 中文称为“流”,通过将集合转换为这么一种叫做 “流” 的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的流水线操作。

换句话说,你只需要告诉流你的要求,流便会在背后自行根据要求对元素进行处理,而你只需要 “坐享其成”。

##二. 流操作

image

整个流操作就是一条流水线,将元素放在流水线上一个个地进行处理。

其中数据源便是原始集合,然后将如 List 的集合转换为 Stream 类型的流,并对流进行一系列的中间操作,比如过滤保留部分元素、对元素进行排序、类型转换等;最后再进行一个终端操作,可以把 Stream 转换回集合类型,也可以直接对其中的各个元素进行处理,比如打印、比如计算总数、计算最大值等等

很重要的一点是,很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,我们来看看一条 Stream 操作的代码:

image

如果是以前,进行这么一系列操作,你需要做个迭代器或者 foreach 循环,然后遍历,一步步地亲力亲为地去完成这些操作;但是如果使用流,你便可以直接声明式地下指令,流会帮你完成这些操作。

有没有想到什么类似的?是的,就像 SQL 语句一样,select username from user where id = 1,你只要说明:“我需要 id 是 1 (id = 1)的用户(user)的用户名(username)”,那么就可以得到自己想要的数据,而不需要自己亲自去数据库里面循环遍历查找。

##三.方法介绍与实践:

###1.获取流:stream() / parallelStream()

   List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
   Stream<Integer> stream = asList.stream();
   System.out.println(stream);

输出结果:clipboard.pngXX.stream() 方法获取的是流,然而我们在实际开发中一般需要获取的是集合

###2.流转换为集合:collect(Collectors.toList())

    List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
    List<Integer> collect1 = asList.stream().collect(Collectors.toList());
    List<Integer> collect2 = asList.stream().collect(toList());
    System.out.println(collect1);
    System.out.println(collect2);

输出结果: 这两种写法获取的结果都是一样的,第二种为简写
clipboard.png

###3.排序 sorted()
eg1:

    List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
    List<Integer> asc = asList.stream().sorted().collect(toList()); //正序
    List<Integer> desc = asList.stream().sorted(Comparator.reverseOrder()).collect(toList());//倒序
    System.out.println(asc);
    System.out.println(desc);

输出结果:clipboard.pngeg2:使用mybatis-plus 查询后对获得的数组中的某个字段进行排序(数据有点多截取了前5条数据进行排序)

    List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<>()); //查询表中所有数据
    按照ATag中SerialNumber字段排序
    List<ATag> collect1 = aTags.stream().sorted(Comparator.comparing(ATag::getSerialNumber)).limit(5).collect(toList());
    List<ATag> collect2 = aTags.stream().sorted(Comparator.comparing(ATag::getSerialNumber).reversed()).limit(5).collect(toList());
    collect1.forEach(System.out::println);
    System.out.println("----------分割线------------");
    collect2.forEach(System.out::println);

输出结果:
360截图20200416173801798.jpg
###4.去重 distinct()
eg1:

    List<Integer> asList = Arrays.asList(10,10,20,20,30,40,50);
    asList.stream().distinct().collect(toList()).forEach(System.out::println);

输出:360截图20200416174543939.jpg
eg2:
如果想要对 List 中某个字段进行去重这里使用 distinct(类::字段) 这种方法是不行的(没有这种筛选条件)
因此,需要借助一下过滤器以及下面学到的filter()方法,实现对 List 中根据某个字段进行去重
参考文章:https://www.jianshu.com/p/77c3b503730c

        //过滤器:
        public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
            ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>(16);
            return t -> map.putIfAbsent(keyExtractor.apply(t),Boolean.TRUE) == null;
        }

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));//查询表中serial_number=6的数据
        aTags.forEach(System.out::println);
        System.out.println("-------------------------分割线-------------------------");
        aTags.stream().filter(distinctByKey(ATag::getNameZh)).collect(toList()).forEach(System.out::println);

输出 :xx.jpg

###5.过滤 filter()
保留 boolean 为 true 的元素

       //查询表中serial_number=6的数据
        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割线-------------------------");
        aTags.stream().filter(x->x.getNameZh().equals("御坂美琴")).collect(toList()).forEach(System.out::println); 

输出:11.jpg

###6.截取(返回前 n 个元素) limit(long n)

        //查询表中serial_number=6的数据
        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割线-------------------------");
        aTags.stream().limit(2).forEach(System.out::println);

输出结果:image.png

###7.跳过 skip(long n)

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().skip(1).limit(2).collect(toList()));

这里使用了skip()和limit()
输出结果:360截图20200417100638948.jpg
tips:
用在 limit(n) 前面时,先去除前 m 个元素再返回剩余元素的前 n 个元素
limit(n) 用在 skip(m) 前面时,先返回前 n 个元素再在剩余的 n 个元素中去除 m 个元素

###8. map(T -> R)
将流中的每一个元素 T 映射为 R(类似类型转换)
eg1:

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割线-------------------------");
        aTags.stream().map(ATag::getNameZh).collect(toList()).forEach(System.out::println);

这里相当于把List转换为List
输出:360截图20200417101622995.jpgeg2:

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        List<Integer> collect = asList.stream().map(x -> x + x * 0.1).mapToInt(T -> T.intValue()).boxed().collect(toList());

输出:1.jpg
###9. flatMap(T -> Stream)
将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流

List<String> list = new ArrayList<>();
list.add("aaa bbb ccc");
list.add("ddd eee fff");
list.add("ggg hhh iii");
list = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());

上面例子中,我们的目的是把 List 中每个字符串元素以" "分割开,变成一个新的 List。
首先 map 方法分割每个字符串元素,但此时流的类型为 Stream<String[ ]>,因为 split 方法返回的是 String[ ] 类型;所以我们需要使用 flatMap 方法,先使用Arrays::stream将每个 String[ ] 元素变成一个 Stream 流,然后 flatMap 会将每一个流连接成为一个流,最终返回我们需要的 Stream

###10.anyMatch(T -> boolean)
流中是否有一个元素匹配给定的 T -> boolean 条件

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割线-------------------------");
        System.out.println(aTags.stream().anyMatch(x -> x.getNameEn().equals("Misaka Miko")));

输出:360截图20200417102715580.jpg

###11. allMatch(T -> boolean)
流中是否所有元素都匹配给定的 T -> boolean 条件,当流中所有元素都符合条件的时候才返回true

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().allMatch(x -> x >= 10));

输出:360截图20200417103151762.jpg

###12.noneMatch(T -> boolean)
流中是否没有元素匹配给定的 T -> boolean 条件(流中有元素匹配到条件返回true否则返回false)

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().noneMatch(x -> x >= 10));

输出:
b.jpg

###13. findAny() 和 findFirst()
findAny():找到其中一个元素 (使用 stream() 时找到的是第一个元素;使用 parallelStream() 并行时找到的是其中一个元素)
findFirst():找到第一个元素

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().findFirst());
        System.out.println(asList.stream().findAny());
        System.out.println(asList.parallelStream().findAny());

输出:
c.jpg

###14.reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)
用于组合流中的元素,如求和,求积,求最大值等

eg1:其中,reduce 第一个参数 0 代表起始值为 0,lambda (a, b) -> a + b 即将两值相加产生一个新值

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割线-------------------------");
        System.out.println(aTags.stream().map(ATag::getParentId).reduce(0L, Long::sum));

输出:2.jpg

eg2:
如果没有初始值,需要考虑结果可能不存在的情况,因此返回的是 Optional 类型如果不需要这种返回类型设置初始值即可

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        Integer reduce1 = asList.stream().reduce(0, (x, y) -> x + y);
        Integer reduce2 = asList.stream().mapToInt(T -> T.intValue()).boxed().reduce(0, (x, y) -> x + y);
        Optional<Integer> reduce3 = asList.stream().reduce((x, y) -> x + y);
        System.out.println("reduce1:"+reduce1 +"\n"+ "reduce2:"+reduce2+"\n"+"reduce3:"+reduce3);

###15. count()
返回流中元素个数,结果为 long 类型

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        asList.stream().count();

###16.遍历流中的每一个元素 forEach()
当然我们也可以通过forEach()遍历流中的每一个元素,然后注入Mapper对流中元素进行CRUD

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割线-------------------------");
        aTags.stream().forEach(item->{
            System.out.println(item.getNameZh());
        });

输出:3.jpg

文章出处
作者:Howie_Y
链接:https://www.jianshu.com/p/0bb4daf6c800
来源:简书

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值