美文网首页java
java-stream(一)

java-stream(一)

作者: go_2021 | 来源:发表于2022-01-04 13:21 被阅读0次

    吾尝终日而思矣,不如须臾之所学以。

    这个流是干啥的?

    流可以简单理解为,把我们业务中数据过滤,分页,求和,分类汇总等一些类似于mysql中的一些聚合函数功能给封装了一下,在写类似功能的时候直接. stream.grougbying(),需要干啥就点啥就行了,写的时候比较丝滑,另外还提供了对fork/join的封装,数据量大的时候直接.stream()换成,. paraealStream() 就可以了,让CPU都忙起来,这操作我就问你,丝滑不?

    这个流有啥特点?
    1. 只会执行一次(只会循环一次)。
    2. 结束操作才会执行。
    3. 不会影响原值。

    只会执行一次如何理解呢?

    List<Integer> integers = Arrays.asList(1, 2, 3);
    long count = integers.stream().filter(x -> {
                System.out.println("a");
                return x > 1;
            }).filter(x ->
            {
                System.out.println("b");
                return x < 3;
            }).count();
    

    会打印aaabbb? aaabb?不对的。会打印aabab。一个元素只会过一遍,被pass,就下一个元素继续。
    第二个惰性加载就是要执行到结束操作才会执行,把上面的例子改一下:

    List<Integer> integers = Arrays.asList(1, 2, 3);
    Stream<Integer> integerStream = integers.stream().filter(x -> {
                System.out.println("a");
                return x > 1;
            }).filter(x ->
            {
                System.out.println("b");
                return x < 3;
            });
    
    

    少个count()方法的调用,那么会打印什么的?是啥都不打印。因为没有执行终止操作,只有中间操作,那哪些是中间操作哪些是终止操作呢?后面会说。
    第三条不会影响原值就很好理解了,不管经历流的操作,integers这个list是不会发生变化的。

    流方法分类?

    大致是这么分类的,中间操作不会触发执行,结束操作才会。
    有无状态可以理解为处理元素是否受前后元素的影响,sorted()排序操作肯定是受前后元素影响啊,所以是划分为有状态
    短路非短路就类似java中的&&&|||区别。
    基于什么实现的?

    因为jdk1.8的函数式接口和lambda表达式的支持。
    有且仅有一个抽象方法的接口一般会有@FunctionalInterface注解函数式接口可以被隐式转换为lambda表达式,可以有多个默认方法。
    lambda表达式:
    (parameters)->expression
    (parameters)->{statements;}
    lambda又可以简化为方法引用更简洁:ClassName::methodName

    • 4大神兽(函数式接口):
      Function(有进有出)、Predicate(有进但出来是个boolean)、Consumer(只进不出)、Supplier(之出不进)
    optional嵌套用法
        // 第一种方式:各种if判断避免了空指针,但是if层级太深,代码冗长
        if (user != null) {
            Address address = user.getAddress();
            if (address != null) {
                Country country = address.getCountry();
                if (country != null) {
                    String couName = country.getCountryName();
                    System.out.println( "第二种方式:" + couName );
                }
            }
        }
    
        // 第二种方式:代码简洁,避免空指针
        String counName = Optional.ofNullable( user )
                .map( User::getAddress )
                .map( Address::getCountry )
                .map( Country::getCountryName )
                .orElse( "china" );
        System.out.println( "第三种方式:" + counName );
    
        // 第三种方式:代码简洁,避免空指针,武林那一步为空都会返回自定义异常
        String countryNameEx = Optional.ofNullable( user )
                .map( User::getAddress )
                .map( Address::getCountry )
                .map( Country::getCountryName )
                .orElseThrow( () -> new RuntimeException( "countryId is null" ) );
    
    有啥需要注意的?
    1. lambda表达式中变量会隐性的添加final关键字的,所以如果你要重新赋值就会报错:
    1. 流不能重复消费还不能修改原值,要不运行就抛异常:



    2. 不能像for循环一样直接return退出方法
    3. 异常相关,增加了异常堆栈的深度,受检异常还不能委托给方法向上抛出,只能自己在lambda中处理:
    integers.stream().forEach(x->{
                try {
                    throw new Exception("dfd");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
    

    感觉好用是好用,但是当我一不注意踩到坑的时候。不知道为啥,我就会想到这张图:


    参考:
    https://www.jianshu.com/p/3d4e76467990
    https://www.cnblogs.com/xzy-/p/10915920.html
    https://blog.csdn.net/Goodbye_Youth/article/details/106879287
    https://www.jianshu.com/p/e81f2f2f68b8
    https://www.cnblogs.com/CarpenterLee/p/6637118.html
    https://blog.csdn.net/iteye_1287/article/details/82540162?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

    相关文章

      网友评论

        本文标题:java-stream(一)

        本文链接:https://www.haomeiwen.com/subject/zieqcrtx.html