美文网首页
Stream常用操作符

Stream常用操作符

作者: 小耗子_20da | 来源:发表于2021-02-18 17:16 被阅读0次

    1、stream创建

    1.1、集合转stream
        List<User> list = new ArrayList<>();
        Stream<User> stream = list.stream();
        Stream<User> parallelStream = list.parallelStream();
    
    1.2、数组转stream

    数组不能转并行流

        int[] array = {1, 2, 3, 4, 5};
        IntStream intStream = Arrays.stream(array);
        Arrays.stream(array);
    
    1.3、用Stream中静态方法创建

    1.3.1、Stream.of

        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
    

    1.3.2、Stream.iterate: 以seed为起始值,根据UnaryOperator中返回值不断迭代

        Stream<Integer> stream2 = Stream
                .iterate(7, new UnaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer integer) {
                        return integer + 3;
                    }
                })
                .limit(4);
        //7,10,13,16
        stream2.forEach(System.out::println);
    

    1.3.3、Stream.generate()不断获取Supplier中 get()方法返回值

        Stream<Double> stream3 = Stream.generate(new Supplier<Double>() {
            @Override
            public Double get() {
                return Math.random();
            }
        }).limit(3);
        //0.014464768543508866 ,0.07501969315371027 ,0.2563750250586957
        stream3.forEach(System.out::println);
    
    1.4、使用 BufferedReader.lines() 方法,将每行内容转成流
        BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));
        Stream<String> lineStream = reader.lines();
        lineStream.forEach(System.out::println);
    
    1.5、使用 Pattern.splitAsStream() 方法,将字符串分隔成流
        Pattern pattern = Pattern.compile(",");
        Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
        stringStream.forEach(System.out::println);
    

    2、中间操作符

    2.1、筛选与切片
    • filter:过滤:筛选出符合条件的元素,返回一个新的stream
    • skip:跳过几个元素
    • limit:取出几个元素 skip 和 limit 可搭配出数据库分页效果
    • distinct:去重,通过流中元素的 hashCode() 和 equals() 去除重复元素
    2.2、映射
    • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
    • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
    2.3、排序
    • sorted():自然排序,流中元素需实现Comparable接口
    • sorted(Comparator com):定制排序,自定义Comparator排序器
    2.4、消费

    peek:如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。

    3、终止操作符

    3.1、匹配、聚合操作
    • allMatch:所有元素都满足条件则返回true,否则返回false
    • noneMatch:所有元素都不满足条件则返回true,否则返回false
    • anyMatch:只要有一个元素满足条件就返回true,都不满足条件则返回false
    • findFirst:返回流中第一个元素
    • findAny:返回流中的任意元素(串行流一般会返回第一个元素,并行流才有效果)
    • count:返回流中元素的总个数
    • max:返回流中元素最大值
    • min:返回流中元素最小值
    • reduce:规约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
        Optional<User> reduce = stream.reduce(new BinaryOperator<User>() {
            @Override
            public User apply(User user, User user2) {
                //第一次:user为流中第一个元素,user2为流中第二个元素
                //第二次:user为第一次apply返回的元素,user2为流中第三个元素
                //第三次:user为第二次apply返回的元素,user2为流中第四个元素
                //以此类推,并行流的顺序没有规律,但是最终的结果和串行流的结果是一样的
                System.out.println("user = " + user.name + "   user2 = " + user2.name);
                return new User(user.name + user2.name, 1, 100);
            }
        });
        System.out.println(reduce);
    
        User identity = new User("曹操", 1, 50);
        User user = stream.reduce(identity, new BinaryOperator<User>() {
            @Override
            public User apply(User user, User user2) {
                //串行流:
                //第一次:user为identity,user2为流中第一个元素
                //第二次:user为第一次apply返回的元素,user2为流中第二个元素
                //第三次:user为第二次apply返回的元素,user2为流中第三个元素
                //以此类推。。。
                
                // 并行流
                //首先会用 identity 与 流中所有元素规约一次,即user = identity ,user2 为流中任意元素
                //然后用上次规约出来的结果再次两两规约,以此类推。。。
                
                System.out.println(Thread.currentThread().getName()+" user = " + user.name + "   user2 = " + user2.name);
                return new User(user.name + user2.name, 1, 100);
            }
        });
        System.out.println(user);
    
        User identity = new User("曹操", 1, 50);
        User user = stream.reduce(identity,
                new BiFunction<User, User, User>() {
                    @Override
                    public User apply(User user, User user2) {
                        System.out.println(Thread.currentThread().getName() + " BiFunction  user = " + user.name + "   user2 = " + user2.name);
                        return new User("BiFunction" + user.name + user2.name, 1, 100);
                    }
                },
                new BinaryOperator<User>() {
                    @Override
                    public User apply(User user, User user2) {
                        //串行流中该方法不会被回调,只会回调BiFunction中的apply方法,结果和2形参的reduce方法一样
    
                        //并行流
                        //首先在BiFunction中将identity与流中元素逐一规约,生成一个新的流
                        //然后将新的流在BinaryOperator中两两规约
                        System.out.println(Thread.currentThread().getName() + " BinaryOperator  user = " + user.name + "   user2 = " + user2.name);
                        return new User("BinaryOperator" + user.name + user2.name, 1, 100);
                    }
                });
        System.out.println(user);
    

    4、收集(collect)

    4.1、归集
    • toList、toSet、toCollection、toMap、toConcurrentMap
        List<User> toList = stream.collect(Collectors.toList());
        Set<User> toSet = stream.collect(Collectors.toSet());
        ArrayList<User> toCollection = stream.collect(Collectors.toCollection(ArrayList::new));
    
        HashMap<String, User> toMap = stream.collect(Collectors.toMap(
                user -> user.name,//第一个函数时接口返回的是map 的key
                user -> user,//第二个函数时接口返回的是map 的value
                (user, user2) -> user2,//两个元素键值对冲突时的解决方案
                HashMap::new
        ));
        //并行的,形参和toMap一样一样的
        ConcurrentMap<String, User> concurrentMap = stream.collect(Collectors.toConcurrentMap(
                user -> user.name,
                user -> user,
                (user, user2) -> user2,
                ConcurrentHashMap::new
                )
        );
    
    4.2、数据统计

    Collectors提供了一系列用于数据统计的静态方法:

    • 计数:count
    • 平均值:averagingInt、averagingLong、averagingDouble
    • 最值:maxBy、minBy
    • 求和:summingInt、summingLong、summingDouble
    • 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
        @Test
        public void count() {
            List<User> list = new ArrayList<>();
            list.add(new User("吕布", 1, 48));
            list.add(new User("貂蝉", 2, 37));
            list.add(new User("刘备", 1, 56));
            list.add(new User("孙尚香", 2, 18));
            list.add(new User("周瑜", 2, 27));
            list.add(new User("小乔", 2, 22));
            
            // 统计数量,等效于list.stream().count(); 或list.size();
            Long count = list.stream().collect(Collectors.counting());
            // 求平均值
            Double average = list.stream().collect(Collectors.averagingDouble(user -> user.age));
            // 求最大值,等效于 list.stream().map(user -> user.age).max(Integer::compare);
            Optional<Integer> max = list.stream().map(user -> user.age).collect(Collectors.maxBy(Integer::compare));
            // 求和,等效于list.stream().mapToInt(user -> user.age).sum();
            Integer sum = list.stream().collect(Collectors.summingInt(user -> user.age));
            // 一次性统计所有信息
            DoubleSummaryStatistics collect = list.stream().collect(Collectors.summarizingDouble(user -> user.age));
    
            System.out.println("总数:" + count);//总数:6
            System.out.println("平均值:" + average);//平均值:34.666666666666664
            System.out.println("求和:" + sum);//求和:208
            System.out.println("所有统计:" + collect);//所有统计:DoubleSummaryStatistics{count=6, sum=208.000000, min=18.000000, average=34.666667, max=56.000000}
        }
    
    4.3、分组分区
    • partitioningBy:分区,分成两块区域,一块是满足条件的,一块不满足条件
    • groupingBy:分组,按指定字段分组,该字段值相同的为元素都会分在一组
        @Test
        public void group() {
            List<User> list = new ArrayList<>();
            list.add(new User("诸葛亮", 1, 48, "法师"));
            list.add(new User("貂蝉", 2, 37, "法师"));
            list.add(new User("鲁班", 1, 56, "射手"));
            list.add(new User("刘禅", 1, 18, "辅助"));
            list.add(new User("韩信", 1, 27, "打野"));
            list.add(new User("孙尚香", 2, 22, "射手"));
    
            //{辅助=[User{name='刘禅', sex=1, age=18}], 打野=[User{name='韩信', sex=1, age=27}], 射手=[User{name='鲁班', sex=1, age=56}, User{name='孙尚香', sex=2, age=22}], 法师=[User{name='诸葛亮', sex=1, age=48}, User{name='貂蝉', sex=2, age=37}]}
            Map<String, List<User>> groupingBy = list.stream().collect(Collectors.groupingBy(user -> user.role));//按user.role分组
            
            //{辅助={1=[User{name='刘禅', sex=1, age=18}]}, 打野={1=[User{name='韩信', sex=1, age=27}]}, 射手={1=[User{name='鲁班', sex=1, age=56}], 2=[User{name='孙尚香', sex=2, age=22}]}, 法师={1=[User{name='诸葛亮', sex=1, age=48}], 2=[User{name='貂蝉', sex=2, age=37}]}}
            Map<String, Map<Integer, List<User>>> collect = list.stream().collect(Collectors.groupingBy(
                    user -> user.role,//按user.role分组
                    Collectors.groupingBy(user -> user.sex)//分组中再按 user.sex分组
            ));
            HashMap<String, Map<Integer, List<User>>> collect1 = list.stream().collect(Collectors.groupingBy(
                    user -> user.role,//按user.role分组
                    HashMap::new,//返回指定map,不指定则是返回Map对象
                    Collectors.groupingBy(user -> user.sex)//分组中再按 user.sex分组
            ));
    
            //{false=[User{name='刘禅', sex=1, age=18}, User{name='孙尚香', sex=2, age=22}], true=[User{name='诸葛亮', sex=1, age=48}, User{name='貂蝉', sex=2, age=37}, User{name='鲁班', sex=1, age=56}, User{name='韩信', sex=1, age=27}]}
            Map<Boolean, List<User>> partitioningBy = list.stream().collect(Collectors.partitioningBy(user -> user.age > 25));
        }
    
    4.4、接合(joining)
    • joining() :字符串直接拼接
    • joining(CharSequence delimiter) :中间加上分隔符
    • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) :加上前缀和后缀
        //由于joining接收的是CharSequence类型,所以需要映射一下
        list.stream().map(user -> user.name).collect(Collectors.joining());
        list.stream().map(user -> user.name).collect(Collectors.joining("-"));
        list.stream().map(user -> user.name).collect(Collectors.joining("-", "前缀", "后缀"));
    
    4.5、规约(reducing)

    规约和stream的规约是一样的,这里不做笔记了

    4.6、映射(mapping)
        //等效于 list.stream().map(user -> user.name).collect(Collectors.toList());
        list.stream().collect(Collectors.mapping(user -> user.name, Collectors.toList()));
    
    4.7、收集后再处理(collectingAndThen)
        String collect = list.stream().collect(
                Collectors.collectingAndThen(
                        Collectors.mapping(user -> user.name, Collectors.joining("-")),
                        s -> "apply " + s
                ));
    
        System.out.println(collect);// apply 诸葛亮-貂蝉-鲁班-刘禅-韩信-孙尚香
    

    相关文章

      网友评论

          本文标题:Stream常用操作符

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