美文网首页
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常用操作符

    1、stream创建 1.1、集合转stream 1.2、数组转stream 数组不能转并行流 1.3、用Stre...

  • Stream并发和分组

    一 Stream的flatMap  操作符定义  函数签名:Stream flatMap(Function<...

  • Java 8 Stream常用的操作符

    简介 在Java 8中API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。在Java中只...

  • Stream流操作符

    一 概述  Stream操作符分为两类中间操作和终止操作。 中间操作:返回一个Stream流 终止操作:返回非St...

  • RxJava2 中常用操作符和Subject常用子类说明

    RxJava2 中常用操作符和Subject常用子类代码练习及说明。ReactiveX 系列所有操作符以及RxJa...

  • 2017-12-07

    python常用操作符分为四种——算数操作符,赋值操作符,比较操作符逻辑操作符 数据结构——标量,序列,映射(字典...

  • RxJava常用操作符

    简介 总结一下RxJava常用的操作符,这样方便自己查询。 常用操作符如下 create()— 通过函数从头开始创...

  • Java8 Stream API 笔记

    Java8 Stream API 笔记 常用的stream操作,做个记录,方便日后使用查询。 [TOC] 1. f...

  • 手把手教你使用 Java 8 Stream 收集器

    前文《Java 8 | Stream 简介与常用方法》介绍了 collect 方法由 Stream 里的值生成一个...

  • 浅析Java8 Stream原理

    文章目录 操作符的分类 流水线的结构 AbstractPipeline Stream的生成源码分析 添加中间操作 ...

网友评论

      本文标题:Stream常用操作符

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