zoukankan      html  css  js  c++  java
  • (二)Java8新增的Stream操作集合

    Java8新增了Stream,IntStream,LongStream,DoubleStream等流式API,这些API代表多个支持串行和并行聚集操作的元素。Stream是一个通用的流接口,而IntStream,LongStream,DoubleStream则代表元素类型为int,long,double的流。
    Stream提供了大量的方法进行聚集操作,这些方法可以是“中间的(intermediate)”,也可以是“末端的(terminal)”。

    Stream介绍:

    先说下Stream的优势:它是java对集合操作的优化,相较于迭代器,使用Stream的速度非常快,并且它支持并行方式处理集合中的数据,默认情况能充分利用cpu的资源。同时支持函数式编程,代码非常简洁。
    Stream是一种用来计算数据的流,它本身并没有存储数据。你可以认为它是对数据源的一个映射或者视图。
    它的工作流程是:获取数据源->进行一次或多次逻辑转换操作->进行归约操作形成新的流(最后可以将流转换成集合)。

    Stream的特性

    1. 中间操作惰性执行:一个流后面可以跟随0到多个中间操作,主要目的是打开流,并没有真正的去计算,而是做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历,并没有消耗资源。还有多个中间操作的话,这里的时间复杂度并不是n个for循环,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在Terminal操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。
    2. 流的末端操作只能有一次: 当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。之后如果想要操作就必须新打开流。

    1.流的生成

    例子一:

            Stream<String> stream1 = (Stream<String>) Stream.<String>builder().add("a").add("b").build();
            stream1.forEach(s -> System.out.println("str:" + s));
    

    例子二:

            Stream<String> stream2 = Stream.of(new String[]{"c", "d"});
            stream2.forEach(s -> System.out.println("str:" + s));
    

    例子三:

            String[] strArray = new String[]{"a", "b", "c"};
            Stream<String> stream3 = Arrays.stream(strArray);
            stream3.forEach(s -> System.out.println("str:" + s));
    

    例子四:

            String[] strArray = new String[]{"a", "b", "c"};
            List<String> list = Arrays.asList(strArray);
            Stream<String> stream4 = list.stream();
            stream4.forEach(s -> System.out.println("str:" + s));
    

    2.流的操作

    流的操作类型分2种:中间操作与末端操作

    2.1中间操作(intermediate ):

    中间操作就是对容器的处理过程,包括:排序(sorted...),筛选(filter,limit,distinct...),映射(map,flatMap...)等

    • filter(Predicate predicate):过滤Stream中所有不符合predicate的元素。

    示例代码:

            List<String> aslist = Arrays.asList("1", "2", "5", "2", "3", "3");
    
            /**
             * filter
             */
            aslist.stream().filter(s -> (Integer.parseInt(s) > 2)).forEach(s -> System.out.println("str:" + s));
    
    //Stream filter method
    Stream<T> filter(Predicate<? super T> predicate);
    

    运行结果:

    str:5
    str:3
    str:3
    
    • mapToXxx(ToXxxFunction mapper):使用ToXxxFunction对流中的元素执行一对一的转换,该方法返回的新流中包含了ToXxxFunction转换生成的所有元素。(映射操作,就像一个管道,可以将流中的元素通过一个函数进行映射,返回一个新的元素。)

    示例代码:

            List<String> aslist = Arrays.asList("1", "2", "5", "232", "3", "13");
    
            /**
             * mapToInt
             */
            aslist.stream().mapToInt(s -> Integer.parseInt(s)).forEach(i -> System.out.println("int:" + i));
    
            /**
             * map
             */
            aslist.stream().map(s -> s.length()).forEach(s -> System.out.println("len:" + s));
    
    //Stream map method
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    
    //Stream mapToInt method
    IntStream mapToInt(ToIntFunction<? super T> mapper);
    

    运行结果:

    int:1
    int:2
    int:5
    int:232
    int:3
    int:13
    len:1
    len:1
    len:1
    len:3
    len:1
    len:2
    
    • peek(Consumer action):依次对每个元素执行一些操作,该方法返回的流与原来流包含相同的元素。该方法主要用于调试

    示例代码:

            /**
             * peek
             */
            aslist.stream().peek(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    //操作
                }
            }).forEach(s -> System.out.println("peek:" + s));
    
    //Stream peek method
    Stream<T> peek(Consumer<? super T> action);
    
    • distinct:该方法用户排序流中所有重复的元素(判断元素重复的标准是使用equals()比较返回true)。这是一个有状态的方法。

    示例代码:

            List<String> aslist = Arrays.asList("1", "2", "5", "3", "3", "2");
    
    
            /**
             * distinct[equals()返回true]
             */
            aslist.stream().distinct().forEach(s -> System.out.println("str:" + s));
    
    //Stream distinct method
    Stream<T> distinct();
    

    运行结果:

    str:1
    str:2
    str:5
    str:3
    
    • sorted:该方法用于保证流中的元素在后续的访问中处于有序状态。这是一个有状态的方法。

    示例代码:

            /**
             * sorted default
             */
            aslist.stream().sorted().forEach(s -> System.out.println("sort1:" + s));
    
            /**
             * sorted comparator
             */
            aslist.stream().sorted(((o1, o2) -> Integer.parseInt(o2) - Integer.parseInt(o1))).forEach(s -> System.out.println("sort2:" + s));
    
    //Stream sorted method
    Stream<T> sorted();
    
    //Stream sorted method
    Stream<T> sorted(Comparator<? super T> comparator);
    

    运行结果:

    sort1:1
    sort1:2
    sort1:2
    sort1:3
    sort1:3
    sort1:5
    sort2:5
    sort2:3
    sort2:3
    sort2:2
    sort2:2
    sort2:1
    
    • limit(long maxSize):该方法用于保证对该流的后续访问中最大允许访问的元素个数,这是一个有状态的,短路方法。
      示例代码:
            List<String> aslist = Arrays.asList("1", "6", "5", "3", "3", "2");
    
    
            /**
             * limit
             */
            aslist.stream().limit(2).forEach(s -> System.out.println("limit:" + s));
    
    //Stream limit method
    Stream<T> limit(long maxSize);
    

    运行结果:

    limit:1
    limit:6
    

    2.2末端操作

    末端方法就是对流的最终操作。当对某个Stream执行末端方法后,该流将会被“消耗”且不可再用。包括sum(),count(),average()等聚合函数。

    • forEach(Consumer action):遍历流中所有元素,对每个元素执行action。

    示例代码:

            List<String> aslist = Arrays.asList("1", "6", "5", "3", "3", "2");
    
            /**
             * forEach
             */
            aslist.stream().forEach(s -> System.out.println("forEach:" + s));
    
    //Stream forEach method
    void forEach(Consumer<? super T> action);
    

    运行结果:

    forEach:1
    forEach:6
    forEach:5
    forEach:3
    forEach:3
    forEach:2
    
    • toArray():将流中所有元素转换为一个数据。
      示例代码:
            List<String> aslist = Arrays.asList("1", "6", "5", "3", "3", "2");
    
            /**
             * toArray
             */
            Object[] objArray = aslist.stream().toArray();
            Arrays.asList(objArray).forEach(s -> System.out.println("toArray:" + s));
    
    //Stream toArray method
    Object[] toArray();
    

    运行结果:

    toArray:1
    toArray:6
    toArray:5
    toArray:3
    toArray:3
    toArray:2
    
    • min() && max() && count() :返回流中的最小,最大值,元素的数量。

    示例代码:

            List<String> aslist = Arrays.asList("1", "6", "5", "3", "3", "2");
    
            /**
             * max && min && count
             */
            System.out.println("max:" + aslist.stream().max(((o1, o2) -> Integer.parseInt(o1) - Integer.parseInt(o2))).get());
            System.out.println("mix:" + aslist.stream().min(((o1, o2) -> Integer.parseInt(o1) - Integer.parseInt(o2))).get());
            System.out.println("count:" + aslist.stream().count());
    
    //Stream max method
    Optional<T> max(Comparator<? super T> comparator);
    //Stream min method
    Optional<T> min(Comparator<? super T> comparator);
    //Stream count method
    long count();
    

    运行结果:

    max:6
    mix:1
    count:6
    
    • anyMatch(Predicate predicate),allMatch(Predicate predicate),noneMatch(Predicate predicate):至少包含一个,是否每个元素都符合,所有元素都不符合 Predicate条件。
      示例代码:
            List<String> aslist = Arrays.asList("1", "6", "5", "3", "3", "2");
    
            /**
             * anyMatch
             */
            System.out.println("anyMatch:" + aslist.stream().anyMatch(s -> s.equals("5")));
    
            /**
             * allMatch
             */
            System.out.println("allMatch:" + aslist.stream().allMatch(s -> s.equals("1")));
    
            /**
             * noneMatch
             */
            System.out.println("noneMatch:" + aslist.stream().noneMatch(s -> s.equals("a")));
    
    //Stream anyMatch method
    boolean anyMatch(Predicate<? super T> predicate);
    
    //Stream allMatchmethod
    boolean allMatch(Predicate<? super T> predicate);
    
    //Stream noneMatchmethod
    boolean noneMatch(Predicate<? super T> predicate);
    

    运行结果:

    anyMatch:true
    allMatch:false
    noneMatch:true
    
    • findFirst(),findAny():返回流中的第一个,任意一个元素。
      示例代码:
            List<String> aslist = Arrays.asList("1", "6", "5", "3", "3", "2");
    
            /**
             * findFirst && findAny
             */
            System.out.println("findFirst:" + aslist.stream().findFirst().get());
            System.out.println("findAny:" + aslist.stream().findAny().get());
    
    //Stream findFirst method
    Optional<T> findFirst();
    
    //Stream findAny method
    Optional<T> findAny();
    
    • reduce:reduce就是减少的意思,它会将集合中的所有值根据规则计算,最后只返回一个结果。它有三个变种,输入参数分别是一个参数、二个参数以及三个参数;
    1. 一个参数的Reduce
    Optional<T> reduce(BinaryOperator<T> accumulator)
    
    //比如,我们找出数组中长度最大的一个数:
    public void test() {
            String address = "中山北路南京大学仙林校区";
            List<String> aList = new ArrayList<>();
            aList.add("南京");
            aList.add("大学");
            aList.add("仙林校区");
            aList.add("仙林大学城");
            aList.add("中山北路");
            Optional<String> a =aList.stream()
                    .reduce((s1, s2) -> s1.length()>=s2.length() ? s1 : s2);
            System.out.println(a.get());//仙林大学城
    }
    
    1. 两个参数的Reduce
    T reduce(T identity, BinaryOperator<T> accumulator)
    
    public void test() {
            String address = "中山北路南京大学仙林校区";
            List<String> aList = new ArrayList<>();
            aList.add("南京");
            aList.add("大学");
            aList.add("仙林校区");
            aList.add("仙林大学城");
            aList.add("中山北路");
            String t="value:";
            String a =aList.stream()
                    .reduce(t, new BinaryOperator<String>() {
                        @Override
                        public String apply(String s, String s2) {
                            return s.concat(s2);
                        }
                    });    
            System.out.println(a);//value:南京大学仙林校区仙林大学城中山北路
    }
    
    1. 三个参数的情况主要是在并行(parallelStream)情况下使用:可以参考(https://blog.csdn.net/icarusliu/article/details/79504602)
    • collect:collect是一个非常常用的末端操作,它本身的参数很复杂,有3个。
    <R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner);
    

    还好,考虑到我们日常使用,java8提供了一个收集器(Collectors),它是专门为collect方法量身打造的接口:我们常常使用collect将流转换成List,Map或Set:

    1. 转换成list:
    Stream<String> stream = Stream.of("I", "love", "you", "too"); 
    List<String> list = stream.collect(Collectors.toList());
    
    1. 转换成Map:
            String address = "中山北路南京大学仙林校区";
            List<String> aList = new ArrayList<>();
            aList.add("南京");
            aList.add("大学");
            aList.add("仙林校区");
            aList.add("仙林大学城");
            aList.add("中山北路");
            String t="value:";
            
            Map<String, Integer> maps = aList.stream().collect(Collectors.toMap(Function.identity(), String::length));
            System.out.println(maps);//{中山北路=4, 大学=2, 仙林大学城=5, 仙林校区=4, 南京=2}
    
    1. 分组操作:分组操作的时候也会将容器转换为Map,这里也说明一下:Collectors.groupingBy(classifier) groupingBy与sql的group by类似,就是一个分组函数。
            String address = "中山北路南京大学仙林校区";
            List<String> aList = new ArrayList<>();
            aList.add("南京");
            aList.add("大学");
            aList.add("仙林校区");
            aList.add("仙林大学城");
            aList.add("中山北路");
            String t="value:";
            
            Map<Integer, List<String>> maps = aList.stream().collect(Collectors.groupingBy(String::length));
            System.out.println(maps);//{2=[南京, 大学], 4=[仙林校区, 中山北路], 5=[仙林大学城]}
    

    3.IntStream

    IntStream是特殊的Stream,但有一些操作符是IntStream独有的。
    以下代码需要单独运行:java.lang.IllegalStateException: stream has already been operated upon or closed

            int[] ints = new int[]{1, 3, 5, 7, 9, 2, 4, 6, 8};
            IntStream intStream = IntStream.of(ints);
    
            System.out.println("max:" + intStream.max().getAsInt());
            System.out.println("min:" + intStream.min().getAsInt());
            System.out.println("avg:" + intStream.average().getAsDouble());
            System.out.println("sum:" + intStream.sum());
            System.out.println("count:" + intStream.count());
    

    参考连接:https://www.cnblogs.com/xjx199403/p/10697430.html

  • 相关阅读:
    Qt学习之路1---软件下载安装及工程简介
    c++之五谷杂粮---3
    c++之五谷杂粮---2
    隐式类型转换
    运算时的数据类型提升
    c++之五谷杂粮---1
    RSYNC--数据迁移、备份
    microsoft .netframework Available Source Code Components
    查看一个文件系统所在的卷组方法
    IE7/8浏览器都不能显示PNG格式图片
  • 原文地址:https://www.cnblogs.com/everyingo/p/12942714.html
Copyright © 2011-2022 走看看