精华内容
下载资源
问答
  • Stream流常用方法

    2020-12-22 04:09:23
    1. 获取Stream流 1. 所有的Collection集合都有对应的Stream(); 2. 可以通过Stream类中的static Stream of()获取 static Stream of(T... t); static Stream of(T t); package com.qfedu.first.streamget; ...
  • 主要介绍了Java Stream 实现合并操作,结合实例形式详细分析了Java Stream 实现合并操作原理与相关注意事项,需要的朋友可以参考下
  • 主要介绍了Java8之Stream流代替For循环操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 主要介绍了java8新特性 stream流的方式遍历集合和数组操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • java8中通过stream流对List类型进行一些操作的测试Demo类
  • 主要介绍了Jdk8中Stream流的使用,让你脱离for循环,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 在Jdk1.8中引入了stream流的概念,这个“流”并不同于IO中的输入和输出流,它是Jdk中的一个类:java.util.stream.Stream,使用流进行处理可以帮助我们提升代码的性能。 1. 常见应用 使用Stream流对集合进行过滤和...
  • Java Stream流(详解)

    千次阅读 多人点赞 2021-08-29 19:23:17
    一、Stream流引入 Lambda表达式,基于Lambda所带来的函数式编程,又引入了一个全新的Stream概念,用于解决集合类库既有的鼻端。(Lambda表达式详解在上篇博客内容) 现有一个需求: 将list集合中姓张的元素...

    一、Stream流引入

            Lambda表达式,基于Lambda所带来的函数式编程,又引入了一个全新的Stream概念,用于解决集合类库既有的鼻端。(Lambda表达式详解在上篇博客内容)

            现有一个需求:

                    将list集合中姓张的元素过滤到一个新的集合中

                    然后将过滤出来的姓张的元素中,再过滤出来长度为3的元素,存储到一个新的集合中

                    1.用常规方法解决需求

            // 已知的知识来解决需求
            List<String> list1 = new ArrayList<>();
            list1.add("张老三");
            list1.add("张小三");
            list1.add("李四");
            list1.add("赵五");
            list1.add("张六");
            list1.add("王八");
    
            ArrayList<String> list2 = new ArrayList<>();
            // 1.将list集合中姓张的元素过滤到一个新的集合中
            for(String name : list1){
                if(name.startsWith("张")){
                    list2.add(name);
                }
            }
            ArrayList list3 = new ArrayList();
            for (String name : list2) {
                if (name.length() == 3){
                    list3.add(name);
                }
            }
            System.out.println(list3);
    
            输出结果:
                [张老三, 张小三]

                  2.用Stream流操作集合,获取流,过滤操作,打印输出

    list1.stream().filter((String name)->name.startsWith("张")).filter((String name)->name.length()==3).forEach((String name)->{
                System.out.println("符合条件的姓名:" + name);
            });

                    ( 看不懂没关系,下面会讲到该方法,这里只是用来引入的)

    二、Stream流的格式

    Stream<T> filter(Predicate<? super T> predicate);
                -----> 参数:public interface Predicate<T>  (函数式接口)
                        ----> 抽象方法:boolean test(T t);
                -----> 参数:public interface Consumer<T>  (函数式接口)
                        ----> 抽象方法:boolean test(T t);

         整体代码看来:流式思想 类似于 工厂车间的“流水线”

                    ( 看不懂没关系,下面会讲到该方法,这里只是用来引入的)

    三、获取流

            根据集合来获取:

                    根据Collection获取流:

                            Collection接口中有一个stream()方法,可以获取流

            default Stream<E> stream()

                    1.根据List获取流

                    2.根据Set获取流

                    3.根据Map获取流

                            3.1根据Map集合的键来获取流

                            3.2根据Map集合的值获取流

                            3.3根据Map集合的键值对对象获取流

                    4.根据数组获取流

            代码演示:

                    1.根据List集合获取流

            // 创建List集合
            List<String> list = new ArrayList<>();
            list.add("张老三");
            list.add("张小三");
            list.add("李四");
            list.add("赵五");
            list.add("张六");
            list.add("王八");
            Stream<String> stream1 = list.stream();

                    2.根据Set集合获取流

            // 创建List集合
            Set<String> set = new HashSet<>();
            list.add("张老三");
            list.add("张小三");
            list.add("李四");
            list.add("赵五");
            list.add("张六");
            list.add("王八");
            Stream<String> stream2 = set.stream();

                    3.根据Map集合获取流

            // 创建Map集合
            Map<Integer,String> map = new HashMap<>();
            map.put(1,"张老三");
            map.put(2,"张小三");
            map.put(3,"李四");
            map.put(4,"赵五");
            map.put(5,"张六");
            map.put(6,"王八");
    
            // 3.1根据Map集合的键获取流
            Set<Integer> map1 = map.keySet();
            Stream<Integer> stream3 = map1.stream();
            // 3.2根据Map集合的值获取流
            Collection<String> map2 = map.values();
            Stream<String> stream4 = map2.stream();
            // 3.3根据Map集合的键值对对象获取瑞
            Set<Map.Entry<Integer, String>> map3 = map.entrySet();
            Stream<Map.Entry<Integer, String>> stream5 = map3.stream();

                    4.根据数组获取流

            // 根据数组获取流
            String[] arr = {"张颜宇","张三","李四","赵五","刘六","王七"};
            Stream<String> stream6 = Stream.of(arr);

            

    四、Stream流的常用方法

            Stream流的常用方法:

                    终结方法:返回值类型不再是Stream接口本身类型的方法,例如:forEach方法和count方法

                    非终结方法/延迟方法:返回值类型仍然是Stream接口自身类型的方法,除了终结方法都是延迟方法。例如:filter,limit,skip,map,conat

    方法名称方法作用方法种类是否支持链式调用
    count统计个数终结方法
    forEach逐一处理终结方法
    filter过滤函数拼接
    limit取用前几个函数拼接
    skip跳过前几个函数拼接
    map映射函数拼接
    concat组合函数拼接

            方法演示:

                    1.count方法:

                            long count (); 统计流中的元素,返回long类型数据

            List<String> list = new ArrayList<>();
            list.add("张老三");
            list.add("张小三");
            list.add("李四");
            list.add("赵五");
            list.add("张六");
            list.add("王八");
    
            long count = list.stream().count();
            System.out.println("集合中的元素个数是:" + count);
    
            输出结果:
                集合中的元素个数是:6

                    2.filter方法:

                            Stream<T> filter(Predicate<? super ?> predicate); 过滤出满足条件的元素

                                    参数Predicate:函数式接口,抽象方法:boolean test (T  t)

                                    Predicate接口:是一个判断接口

            // 获取stream流
            Stream<String> stream = Stream.of("张老三", "张小三", "李四", "赵五", "刘六", "王七");
            // 需求:过去出姓张的元素
            stream.filter((String name)->{
                return name.startsWith("张");
            }).forEach((String name)->{
                System.out.println("流中的元素" + name);
            });

                            (上面引入Stream流时,就用到了这个方法)

                    3.forEach方法

                           void forEach(Consumer<? super T> action):逐一处理流中的元素
                参数 Consumer<? super T> action:函数式接口,只有一个抽象方法:void accept(T t);

                            注意:

                                    1.此方法并不保证元素的逐一消费动作在流中是有序进行的(元素可能丢失)

                                    2.Consumer是一个消费接口(可以获取流中的元素进行遍历操作,输出出去),可以使用Lambda表达式

            List<String> list = new ArrayList<>();
            list.add("张老三");
            list.add("张小三");
            list.add("李四");
            list.add("赵五");
            list.add("张六");
            list.add("王八");
    
            // 函数模型:获取流 --> 注意消费流中的元素
            list.stream().forEach((String name)->{
                System.out.println(name);
            });
    
            输出结果:
                张老三
                张小三
                李四
                赵五
                张六
                王八

                    4.limit方法

                            Stream<T> limit(long maxSize);   取用前几个元素

                            注意:

                                    参数是一个long 类型,如果流的长度大于参数,则进行截取;否则不进行操作

            // 获取流的长度
            Stream<String> stream1 = Stream.of("张老三", "张小三", "李四", "赵五", "刘六", "王七");
            // 需求:保留前三个元素
            stream1.limit(3).forEach((String name)->{
                System.out.println("流中的前三个元素是:" + name);
            });
    
            输出结果:
                流中的前三个元素是:张老三
                流中的前三个元素是:张小三
                流中的前三个元素是:李四

                    5.map方法

                            <r> Stream <R> map(Function<? super T,? exception R> mapper;
                                参数Function<T,R>:函数式接口,抽象方法:R apply(T t);
                                    Function<T,R>:其实就是一个类型转换接口(T和R的类型可以一致,也可以不一致)

            // 获取Stream流
            Stream<String> stream1 = Stream.of("11","22","33","44","55");
            // 需求:把stream1流中的元素转换为int类型
            stream1.map((String s)->{
               return Integer.parseInt(s); // 将String类型的s进行转换为Integer类型的元素,并返回
            }).forEach((Integer i)->{
                System.out.println(i);  // 将转换后的int类型的元素逐一输出
            });
    
            输出结果:
                11
                22
                33
                44
                55
    

                    6.skip方法

                        Stream<T> skip(long n);     跳过前几个元素
                        注意:
                            如果流的当前长度大于n,则跳过前n个,否则将会得到一个长度为0的空流

            // 获取stream流
            Stream<String> stream = Stream.of("张老三", "张小三", "李四", "赵五", "刘六", "王七");
    
            stream.skip(3).forEach((String name)->{
                System.out.println("跳过前三个,打印剩下的" + name);
            });
    
            输出结果:
                跳过前三个,打印剩下的赵五
                跳过前三个,打印剩下的刘六
                跳过前三个,打印剩下的王七
    

                    7.concat方法

        public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
                --> 合并两个流

             Stream<String> stream1 = Stream.of("11","22","33","44","55");
            Stream<String> stream2 = Stream.of("张颜宇", "张三", "李四", "赵五", "刘六", "王七");
    
            // 需求:合并两个流
            Stream<String> stream = Stream.concat(stream1,stream2);
            stream.forEach((String name)->{
                System.out.print(name);
            });
    
            输出结果:
                1122334455张颜宇张三李四赵五刘六王七

    五、收集Stream流

            Stream流中提供了一个方法,可以把流中的数据收集到单例集合中

                    <R, A> R collect(Collector<? super T, A, R> collector);     把流中的数据手机到单列集合中
                        返回值类型是R。R指定为什么类型,就是手机到什么类型的集合
                        参数Collector<? super T, A, R>中的R类型,决定把流中的元素收集到哪个集合中
                        参数Collector如何得到 ?,可以使用 java.util.stream.Collectors工具类中的静态方法:
                            - public static <T> Collector<T, ?, List<T>> toList():转换为List集合
                            - public static <T> Collector<T, ?, Set<T>> toSet() :转换为Set集合

            List<String> list2 = new ArrayList<>();
            list2.add("张老三");
            list2.add("张小三");
            list2.add("李四");
            list2.add("赵五");
            list2.add("张六");
            list2.add("王八");
    
            // 需求:过滤出姓张的并且长度为3的元素
            Stream<String> stream = list2.stream().filter((String name) -> {
                return name.startsWith("张");
            }).filter((String name) -> {
                return name.length() == 3;
            });
    
            // stream 收集到单列集合中
            List<String> list = stream.collect(Collectors.toList());
            System.out.println(list);
    
            // stream 手机到单列集合中
            Set<String> set = stream.collect(Collectors.toSet());
            System.out.println(set);

                            

    展开全文
  • Stream流的获取方式与常用方法

    千次阅读 2020-08-02 17:53:12
    1. 获取Stream流的方法 java.util。stream.Stream是Java 8新加入的最常用的流接口。(这并不是一个函数式接口); 获取一个流非常简单,有以下几种常用的方式获取流. 所有的Collection结合都可以通过stream默认方法...

    1. 获取Stream流的方法

    java.util。stream.Stream是Java 8新加入的最常用的流接口。(这并不是一个函数式接口);
    获取一个流非常简单,有以下几种常用的方式获取流.

    • 所有的Collection结合都可以通过stream默认方法获取流;
      default Stream Stream()
    • Stream接口的静态方法of可以获取数组对应的流。
      static Stream of (T…values)
      参数是一个可变参数,那么我们就可以传递一个数组
    package com.Stream;
    
    import java.util.*;
    import java.util.stream.Stream;
    
    /*
        java.util。stream.Stream<T>是Java 8新加入的最常用的流接口。(这并不是一个函数式接口)
        获取一个流非常简单,有以下几种常用的方式获取流;
            所有的Collection结合都可以通过stream默认方法获取流;
                 default Stream<E> Stream()
            Stream接口的静态方法of可以获取数组对应的流。
                 static<T> Stream<T> of (T...values)
                 参数是一个可变参数,那么我们就可以传递一个数组
     */
    public class Demo03GetStream {
        public static void main(String[] args) {
            //把集合转换为Stream流
            List<String> list = new ArrayList<>();
            Stream<String> stream1 = list.stream();
    
            Set<String> set = new HashSet<>();
            Stream<String> stream2 = set.stream();
    
            Map<String,String> map = new HashMap<>();
            //获取键,存储到一个Set集合中
            Set<String> keySet = map.keySet();
            Stream<String> stream3 = keySet.stream();
    
            //获取值,存储到一个Collection集合中
            Collection<String> values = map.values();
            Stream<String> stream4 = values.stream();
    
            //获取键值对(键与值的映射关系 entrySet)
            Set<Map.Entry<String, String>> entries = map.entrySet();
    
            Stream<Map.Entry<String, String>> stream5 = entries.stream();
    
            //把数组转换为Stream流
            Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5, 6);
            //可变参数可以传递数组
            Integer[] arr = {1,2,3,4,5};
            Stream<Integer> stream7 = Stream.of(arr);
    
            String[] arr2 = {"a","dd","cc"};
            Stream<String> stream8 = Stream.of(arr2);
        }
    }
    
    

    2.Stream流中常用方法_forEach

    流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

    • 延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方 法均为延迟方法。)
    • 终结方法:返回值类型不再是 Stream 接口自身类型的方法
    void forEach(Consumer<? super T> action);
    
    • 该方法接收一个Consumer接口函数,会将每一个流元素交给函数进行处理。
    • Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式,消费数据。
    • 简单记:
      forEach方法,用来遍历流中的数据;
      是一个终结方.法,遍历之后就不能继续调用Stream流中的其他方法。
    package com.Stream;
    
    import java.util.stream.Stream;
    
    /*
        Stream流中常用方法_forEach
        void forEach(Consumer<? super T> action);
        该方法接收一个Consumer接口函数,会将每一个流元素交给函数进行处理。
        Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式,消费数据
    
        简单记:
            forEach方法,用来遍历流中的数据
            是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法
     */
    public class Dem04Stream_forEach {
        public static void main(String[] args) {
            //获取一个Stream流
            Stream<String> stream = Stream.of("张三", "赵四", "王五", "李六", "田七");
            //使用Stream流中的方法forEach对Stream流中的数据进行遍历
        /*    stream.forEach((String name)->{
                System.out.println(name);
            });*/
            stream.forEach( name-> System.out.println(name));
        }
    }
    
    

    3.Stream流中的常用方法——filter:用于对Stream流中的数据进行过滤

    Stream<T> filter(Predicate<? super T> predicate);
    
    • filter方法的参数Predicate是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤
    • Predicate中的抽象方法:
      boolean test(T t);
    package com.Stream;
    
    import java.util.stream.Stream;
    
    /*
        Stream流中的常用方法——filter:用于对Stream流中的数据进行过滤
        Stream<T> filter(Predicate<? super T> predicate);
        filter方法的参数Predicate是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤
        Predicate中的抽象方法:
              boolean test(T t);
     */
    public class Demo05Stream_filter {
        public static void main(String[] args) {
            //创建一个Stream流
            Stream<String> stream = Stream.of("张三丰", "张翠山", "周芷若", "赵敏", "张无忌");
            //对Stream流中的元素进行过滤,只要姓张的人
           Stream stream2 = stream.filter((String name)->{return name.startsWith("张");});
           //遍历stream2
            stream2.forEach(name-> System.out.println(name));
    
            /*
            Stream流属于管道流,只能被消费(使用)一次
            第一个Stream流调用完毕方法,数据就会流转到下一个Stream上
            而这时第一个Stream流已经使用完毕,就会关闭了
            所以第一个Stream流就不能调用方法了
            IllegalStateException: stream has already been operated upon or closed
             */
            //遍历Stream流
            stream.forEach(name-> System.out.println(name));
        }
    }
    
    

    4.如果需要将流中的元素映射到另一个流中,可以使用map方法。

    <R> Stream<R> map(Function<? super T,? extends R> mapper);
    
    • 该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转化为另一种R类型的流。
    • Function中的抽象方法:
      R apply(T t);
    package com.Stream;
    
    import java.util.stream.Stream;
    
    /*
        如果需要将流中的元素映射到另一个流中,可以使用map方法。
        <R> Stream<R> map(Function<? super T,? extends R> mapper);
        该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转化为另一种R类型的流。
        Function中的抽象方法:
         R apply(T t);
     */
    public class Demo06Stream_map {
        public static void main(String[] args) {
            //获取一个String类型的Stream流
            Stream<String> stream = Stream.of("1", "2", "3", "4", "5", "6");
            //使用map方法,把字符串类型的整数,转换(映射)为Integer类型的整数
            Stream<Integer> stream2 = stream.map((String s)->{
               return Integer.parseInt(s);
            });
            //遍历stream2
            stream2.forEach(i-> System.out.println(i));
        }
    }
    
    

    5.Stream流中常用方法_count:用于统计Stream流中元素的个数

    • long count();
    • count方法是一个终结方法,返回值是一个long类型的整数;所以不能再继续调用Stream流中的其他方法了
    package com.Stream;
    
    import java.util.ArrayList;
    import java.util.stream.Stream;
    
    /*
        Stream流中常用方法_count:用于统计Stream流中元素的个数
        long count();
        count方法是一个终结方法,返回值是一个long类型的整数
        所以不能再继续调用Stream流中的其他方法了
     */
    public class Demo07Stream_count {
        public static void main(String[] args) {
            //获取一个Stream流
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            list.add(5);
            list.add(6);
            Stream<Integer> stream = list.stream();
            long count = stream.count();
            System.out.println(count);
        }
    }
    
    

    6.Stream流中常用方法——limit:用于截取流中的元素

    • limit方法可以对流进行截取,只取前n个。方法签名:
    Stream<T> limit(long maxSize);
    
    • 参数是一个long型,如果集合当前长度大于参数则进行截取,否则不进行操作
    • limit方法是一个延迟方法,只是对流中的元素进行截取,返回的是一个新的流,所以可以继续调用Stream流中的其他方法
    package com.Stream;
    
    import java.util.stream.Stream;
    
    /*
        Stream流中常用方法——limit:用于截取流中的元素
        limit方法可以对流进行截取,只取前n个。方法签名:
        Stream<T> limit(long maxSize);
             参数是一个long型,如果集合当前长度大于参数则进行截取,否则不进行操作
        limit方法是一个延迟方法,只是对流中的元素进行截取,返回的是一个新的流,所以可以继续调用Stream流中的其他方法
     */
    public class Demo08Stream_limit {
        public static void main(String[] args) {
            //获取一个Stream流
            String[] arr = {"美羊羊","喜羊羊","懒羊羊","灰太狼","红太狼","小灰灰"};
            Stream<String> stream = Stream.of(arr);
            //使用limit方法对Stream流中的元素进行截取,只要前3个元素
            Stream<String> strean2 = stream.limit(3);
            //遍历stream2流
            strean2.forEach(name-> System.out.println(name));
        }
    }
    
    

    7.Stream流中常用方法——skip:用于跳过元素

    • 如果希望跳过前几个元素,可以使用skip方法获取一个截取之后的新流;
    Stream<T> skip(long n);
    
    • 如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流
    package com.Stream;
    
    import java.util.stream.Stream;
    
    /*
        Stream流中常用方法——skip:用于跳过元素
        如果希望跳过前几个元素,可以使用skip方法获取一个截取之后的新流;
        Stream<T> skip(long n);
            如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流
     */
    public class Demo09Stream_skip {
        public static void main(String[] args) {
            //获取一个Stream流
            String[] arr = {"美羊羊","喜羊羊","懒羊羊","灰太狼","红太狼","小灰灰"};
            Stream<String> stream = Stream.of(arr);
            //使用skip方法跳过前3个元素
            Stream<String> stream2 = stream.skip(3);
    
            //遍历stream2流
            stream2.forEach(name-> System.out.println(name));
        }
    }
    
    

    8.Stream流中的常用方法——concat:用于把流组合到一起

    • 如果有两个流,希望合并成为一个流,那么可以使用静态方法concat
    static <T> Stream<T> concat (Stream<? extends T> a,Stream <? extends T> b)
    
    package com.Stream;
    
    import java.util.stream.Stream;
    
    /*
        Stream流中的常用方法——concat:用于把流组合到一起
        如果有两个流,希望合并成为一个流,那么可以使用静态方法concat
        static <T> Stream<T> concat (Stream<? extends T> a,Stream <? extends T> b)
     */
    public class Demo10Stream_concat {
        public static void main(String[] args) {
            //创建一个Stream流
            Stream<String> stream1 = Stream.of("张三丰", "张翠山", "周芷若", "赵敏", "张无忌");
            //获取一个Stream流
            String[] arr = {"美羊羊","喜羊羊","懒羊羊","灰太狼","红太狼","小灰灰"};
            Stream<String> stream2 = Stream.of(arr);
    
            //把以上两个流组合一个流
            Stream<String> concat = Stream.concat(stream1, stream2);
            //遍历concat
            concat.forEach(name-> System.out.println(name));
        }
    }
    
    
    展开全文
  • Stream流排序

    千次阅读 2021-01-16 11:58:55
    很多时候由于需求的复杂性,很多直接从数据库查出的数据并不能直接返回前端,需要进行处理,处理之后又需要排序,这时候一般都会使用Stream流的Sort排序场景一:普通排序正序(升序)list=list.stream().sorted()....

    很多时候由于需求的复杂性,很多直接从数据库查出的数据并不能直接返回前端,需要进行处理,处理之后又需要排序,这时候一般都会使用Stream流的Sort排序

    场景一:普通排序

    正序(升序)

    list=list.stream().sorted().collect(Collectors.toList());

    或者

    list.stream().sorted(Comparator.comparing(Student::getAge))

    倒序(降序)

    list.stream().sorted(Comparator.reverseOrder())

    或者

    list.stream().sorted(Comparator.comparing(Student::getAge).reversed())

    场景二:含空值排序

    有时候数据库会有一些错误数据,但是又要求程序不能报错,这怎么办呢?

    1.含空值的正序(升序)排序(按创建时间排序)

    list=list.stream().sorted(Comparator.comparing(l -> l.getCreateTime(), Comparator.nullsFirst(Date::compareTo).reversed())).collect(Collectors.toList());

    如果创建时间可能为空就会报错

    2.含空值的倒序(降序)排序

    nullsFirst:空值放第一位

    list=list.stream().sorted(Comparator.comparing(l -> l.getCreateTime(), Comparator.nullsFirst(Date::compareTo).reversed())).collect(Collec

    展开全文
  • Java Stream 高级使用全解

    千次阅读 2020-12-26 18:38:56
    Java Stream 高级使用全解一 基本汇总1. 创建2. 中间操作3. 终止操作二 经验累积1. 统计1.1 取最大值1.2 取最小值1.3 取总和值1.4 取平均值2. 过滤2.1 获取最近时间3. 排序3.1 根据字段排序4. 分组4.1 获取字段...

    image-20201218222951165

    Java 强大的 stream 流处理,必会!

    无状态:指元素的处理不受之前元素的影响;

    有状态:指该操作只有拿到所有元素之后才能继续下去。

    非短路操作:指必须处理所有元素才能得到最终结果;

    短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。

    一 基本汇总

    1. 创建流

    1.1 使用Collection下的 stream() 和 parallelStream() 方法

    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream(); //获取一个顺序流
    Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
    

    1.2 使用Arrays 中的 stream() 方法,将数组转成流

    Integer[] nums = new Integer[10];
    Stream<Integer> stream = Arrays.stream(nums);
    

    1.3 使用Stream中的静态方法:of()、iterate()、generate()

    Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
    Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
    stream2.forEach(System.out::println); // 0 2 4 6 8 10
    Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
    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:过滤流中的某些元素
      limit(n):获取n个元素
      skip(n):跳过n元素,配合limit(n)可实现分页
      distinct:通过流中元素的 hashCode() 和 equals() 去除重复元素

    Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);
    Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14
        .distinct() //6 7 9 8 10 12 14
        .skip(2) //9 8 10 12 14
        .limit(2); //9 8
    newStream.forEach(System.out::println);
    

    2.2 映射
      map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
      flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

    List<String> list = Arrays.asList("a,b,c", "1,2,3");
    //将每个元素转成一个新的且不带逗号的元素
    Stream<String> s1 = list.stream().map(s -> s.replaceAll(",", ""));
    s1.forEach(System.out::println); // abc 123
    Stream<String> s3 = list.stream().flatMap(s -> {
        //将每个元素转换成一个stream
        String[] split = s.split(",");
        Stream<String> s2 = Arrays.stream(split);
        return s2;
    });
    s3.forEach(System.out::println); // a b c 1 2 3
    

    2.3 排序
      sorted():自然排序,流中元素需实现Comparable接口
      sorted(Comparator com):定制排序,自定义Comparator排序器

    List<String> list = Arrays.asList("aa", "ff", "dd");
    //String 类自身已实现Compareable接口
    list.stream().sorted().forEach(System.out::println);// aa dd ff
    Student s1 = new Student("aa", 10);
    Student s2 = new Student("bb", 20);
    Student s3 = new Student("aa", 30);
    Student s4 = new Student("dd", 40);
    List<Student> studentList = Arrays.asList(s1, s2, s3, s4);
    //自定义排序:先按姓名升序,姓名相同则按年龄升序
    studentList.stream().sorted(
        (o1, o2) -> {
            if (o1.getName().equals(o2.getName())) {
            	return o1.getAge() - o2.getAge();
            } else {
            	return o1.getName().compareTo(o2.getName());
            }
        }
    ).forEach(System.out::println); 
    

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

    Student s1 = new Student("aa", 10);
    Student s2 = new Student("bb", 20);
    List<Student> studentList = Arrays.asList(s1, s2);
    studentList.stream()
        .peek(o -> o.setAge(100))
        .forEach(System.out::println);
    //结果:
    Student{name='aa', age=100}
    Student{name='bb', age=100}
    

    3. 终止操作

    3.1 匹配、聚合操作
      allMatch:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
      noneMatch:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
      anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
      findFirst:返回流中第一个元素
      findAny:返回流中的任意元素
      count:返回流中元素的总个数
      max:返回流中元素最大值
      min:返回流中元素最小值

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    boolean allMatch = list.stream().allMatch(e -> e > 10); //false
    boolean noneMatch = list.stream().noneMatch(e -> e > 10); //true
    boolean anyMatch = list.stream().anyMatch(e -> e > 4); //true
    Integer findFirst = list.stream().findFirst().get(); //1
    Integer findAny = list.stream().findAny().get(); //1
    long count = list.stream().count(); //5
    Integer max = list.stream().max(Integer::compareTo).get(); //5
    Integer min = list.stream().min(Integer::compareTo).get(); //1
    

    3.2 规约操作
      Optional reduce(BinaryOperator accumulator):第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
      T reduce(T identity, BinaryOperator accumulator):流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。
      U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator combiner):在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行规约。

    //经过测试,当元素个数小于24时,并行时线程数等于元素个数,当大于等于24时,并行时线程数为16
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24);
    Integer v = list.stream().reduce((x1, x2) -> x1 + x2).get();
    System.out.println(v); // 300
    Integer v1 = list.stream().reduce(10, (x1, x2) -> x1 + x2);
    System.out.println(v1); //310
    Integer v2 = list.stream().reduce(0,
        (x1, x2) -> {
            System.out.println("stream accumulator: x1:" + x1 + " x2:" + x2);
            return x1 - x2;
        },
        (x1, x2) -> {
            System.out.println("stream combiner: x1:" + x1 + " x2:" + x2);
            return x1 * x2;
    });
    System.out.println(v2); // -300
    Integer v3 = list.parallelStream().reduce(0,
        (x1, x2) -> {
            System.out.println("parallelStream accumulator: x1:" + x1 + " x2:" + x2);
            return x1 - x2;
        },
        (x1, x2) -> {
            System.out.println("parallelStream combiner: x1:" + x1 + " x2:" + x2);
            return x1 * x2;
    });
    System.out.println(v3); //197474048
    

    3.3 收集操作

    collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。
      Collector<T, A, R> 是一个接口,有以下5个抽象方法:
      Supplier<A> supplier():创建一个结果容器A
      BiConsumer<A, T> accumulator():消费型接口,第一个参数为容器A,第二个参数为流中元素T。
      BinaryOperator<A> combiner():函数接口,该参数的作用跟上一个方法(reduce)中的combiner参数一样,将并行流中各 个子进程的运行结果(accumulator函数操作后的容器A)进行合并。
      Function<A, R> finisher():函数式接口,参数为:容器A,返回类型为:collect方法最终想要的结果R。
      Set<Characteristics> characteristics():返回一个不可变的Set集合,用来表明该Collector的特征。有以下三个特征:
      CONCURRENT:表示此收集器支持并发。(官方文档还有其他描述,暂时没去探索,故不作过多翻译)
      UNORDERED:表示该收集操作不会保留流中元素原有的顺序。
      IDENTITY_FINISH:表示finisher参数只是标识而已,可忽略。

    3.3.1 Collector 工具库:Collectors

    Student s1 = new Student("aa", 10, 1);
    Student s2 = new Student("bb", 20, 2);
    Student s3 = new Student("cc", 10, 3);
    List<Student> list = Arrays.asList(s1, s2, s3);
    //转成list
    List<Integer> ageList = list.stream().map(Student::getAge).collect(Collectors.toList()); // [10, 20, 10]
    //转成set
    Set<Integer> ageSet = list.stream().map(Student::getAge).collect(Collectors.toSet()); // [20, 10]
    //转成map,注:key不能相同,否则报错
    Map<String, Integer> studentMap = list.stream().collect(Collectors.toMap(Student::getName, Student::getAge)); // {cc=10, bb=20, aa=10}
    //字符串分隔符连接
    String joinName = list.stream().map(Student::getName).collect(Collectors.joining(",", "(", ")")); // (aa,bb,cc)
    //【聚合操作】
    //1.学生总数
    Long count = list.stream().collect(Collectors.counting()); // 3
    //2.最大年龄 (最小的minBy同理)
    Integer maxAge = list.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // 20
    //3.所有人的年龄
    Integer sumAge = list.stream().collect(Collectors.summingInt(Student::getAge)); // 40
    //4.平均年龄
    Double averageAge = list.stream().collect(Collectors.averagingDouble(Student::getAge)); // 13.333333333333334
    // 带上以上所有方法
    DoubleSummaryStatistics statistics = list.stream().collect(Collectors.summarizingDouble(Student::getAge));
    System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage());
    //分组
    Map<Integer, List<Student>> ageMap = list.stream().collect(Collectors.groupingBy(Student::getAge));
    //多重分组,先根据类型分再根据年龄分
    Map<Integer, Map<Integer, List<Student>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(Student::getType, Collectors.groupingBy(Student::getAge)));
    //分区
    //分成两部分,一部分大于10岁,一部分小于等于10岁
    Map<Boolean, List<Student>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10));
    //规约
    Integer allAge = list.stream().map(Student::getAge).collect(Collectors.reducing(Integer::sum)).get(); //40
    

    3.3.2 Collectors.toList() 解析

    //toList 源码
    public static <T> Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                (left, right) -> {
                    left.addAll(right);
                    return left;
                }, CH_ID);
    }
    
    //为了更好地理解,我们转化一下源码中的lambda表达式
    public <T> Collector<T, ?, List<T>> toList() {
        Supplier<List<T>> supplier = () -> new ArrayList();
        BiConsumer<List<T>, T> accumulator = (list, t) -> list.add(t);
        BinaryOperator<List<T>> combiner = (list1, list2) -> {
            list1.addAll(list2);
            return list1;
        };
        Function<List<T>, List<T>> finisher = (list) -> list;
        Set<Collector.Characteristics> characteristics = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
    
        return new Collector<T, List<T>, List<T>>() {
            @Override
            public Supplier supplier() {
                return supplier;
            }
    
            @Override
            public BiConsumer accumulator() {
                return accumulator;
            }
    
            @Override
            public BinaryOperator combiner() {
                return combiner;
            }
    
            @Override
            public Function finisher() {
                return finisher;
            }
    
            @Override
            public Set<Characteristics> characteristics() {
                return characteristics;
            }
        };
    }
    

    二 经验累积

    1. 统计

    1.1 取最大值

    // List<Map>
    int max = list.stream().mapToInt(
    	m -> m.get("number") != null ? Integer.parseInt(m.get("number").toString()) : 0
    ).max().getAsInt();
    

    1.2 取最小值

    // List<Map>
    int min = list.stream().mapToInt(
        m -> m.get("number") != null ? Integer.parseInt(m.get("number").toString()) : 0
    ).min().getAsInt();
    

    1.3 取总和值

    // List<对象>
    (int)list.stream().mapToInt(n -> n.getClickNum()).summaryStatistics().getSum();
    (int)list.stream().mapToInt(n -> n.getReplyNum()).summaryStatistics().getSum();
    
    // List<Map>
    int sum = list.stream().mapToInt(
    	m -> m.get("number") != null ? Integer.parseInt(m.get("number").toString()) : 0
    ).sum();
    

    1.4 取平均值

    // List<Map>
    double avg = list.stream().mapToInt(
        m -> m.get("number") != null ? Integer.parseInt(m.get("number").toString()) : 0
    ).average().getAsDouble();
    

    2. 过滤

    2.1 获取最近时间

    long date = list.stream().filter(x -> x!=null).filter(y -> y.getNewReplyTime()!=null).mapToLong(n -> n.getNewReplyTime().getTime()).summaryStatistics().getMax();
    if(date>0) forumPlateVo.setNewReplyTime(new Date(date));
    

    3. 排序

    3.1 根据字段排序

    // Comparator.comparing(排序字段)  reversed() 倒序
    List list = list.stream().sorted(Comparator.comparing(ForumPlateVo::clickNum).reversed()).collect(Collectors.toList());
    
    //将 List<Map> 按照热力值进行倒序:Comparator.comparing(取元素值m) -> 转为整数    进而排序
    List<Map> list = (List<Map>) topList.stream().sorted(Comparator.comparing((Map<String, Object> m) -> (Integer.parseInt(m.get("heatvalue").toString()))).reversed()).collect(Collectors.toList());
    

    4. 分组

    4.1 获取字段出现次数

    // List<对象>
    int count = list.stream().collect(Collectors.groupingBy(ActivityLottery::getOpenId)).size();
    
    // List<Map>
    // 两列:去重的用户团标识和团中用户数量
    Map<Object, Long> ucMaps = list.stream().collect(Collectors.groupingBy(e -> e.get("usercliqueId"), Collectors.counting()));
    

    4.2 过滤并获取指定字段列表

    // List<Map>
    // 所有的用户团中的用户:.filter()过滤id相同的团、.map()取出映射的值、去重、组成List集合
    List<String> userIds = list.stream().filter(m -> ucId.toString().equals(m.get("usercliqueId").toString()))
        .map(m -> m.get("userId").toString()).distinct().collect(Collectors.toList());
    
    展开全文
  • JDK Stream流使用介绍

    千次阅读 2019-07-20 08:54:46
    Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。通常我们需要多行代码才能完成的操作,借助于Stream流式处理可以很简单的实现。   &...
  • Stream流-分组操作

    万次阅读 多人点赞 2020-07-11 22:21:05
    Stream流-分组操作 文章目录Stream流-分组操作方法1,`groupingBy(Function)`方法2,`groupingBy(Function,Collector)`方法3:`groupingBy(Function,Supplier,Collector)` Collectors.groupingBy()3个方法的使用...
  • Java Stream流及其方法使用

    千次阅读 2019-07-26 10:20:07
    //因为传的接口是consumer 接口,而stream流,是管道流,只能消费一次, //所以消费一次之后,不能在进行第二次消费。 Stream<String> stream = Stream.of("张三", "李四", "王五","张无忌","周芷若"); // stream...
  • Stream流

    千次阅读 2018-08-21 14:39:36
    Stream流  流式思想 流操作 获取流   常用方法 遍历:forEach 过滤:filter 映射:map    Stream流  流式思想  Stream流是一个集合元素的函数模型,并不是集合,也不是数据结构,其本身并不存储...
  • JDK8的 stream流详解-转载

    万次阅读 多人点赞 2019-04-13 09:16:48
    Java8新特性:Stream流详解 本文章 转载自头条网, 只是觉得好用很详细,所以自己收集 做下笔记,不做任何商业用途,不收任何费用,不喜勿喷。 本文是转载,希望不要涉及到文章版权,只是自己做笔记。_________ 这...
  • Java8 Stream流使用及其基本原理

    千次阅读 2021-01-12 18:06:15
    Stream流,是对集合对象操作的增强基本使用比如有一个Person类的集合:List personList,可以通过stream()对集合中的元素进行操作,下面的操作流程可以归纳为 过滤-映射-收集。List personIdList = personList....
  • 一、Stream流 1、概念 Stream:是一个接口,功能类似于流水线的工作,主要就是用于对数据进行过滤。流(Stream)与集合类似,但集合中保存的是数据,而Stream中保存对集合或数组数据的操作。 作用:使用Stream对数据...
  • JDK8新特性之Stream流详解

    千次阅读 2019-06-24 00:03:52
    JDK8新特性之Stream流式操作1 概述 1 概述   是 JDK8 新增的成员,允许以声明性方式处理数据集合,可以把 Stream 看作是遍历数据集合的一个高级迭代器   使用的好处: 代码以声明性方式书写:说明想要...
  • JAVA的stream流操作详细解析

    千次阅读 2020-09-16 11:15:03
    java的stram流操作为什么需要 Stream流与集合的区别对比:原始集合操作与Stream集合操作流的组成流操作的分类流的使用 为什么需要 Stream Stream 作为 Java 8 的一大亮点,它专注于对集合对象进行各种非常便利、高效...
  • Stream流(Stream,Lambda)

    千次阅读 2020-06-04 17:54:34
    Stream流是Java8提供的一个新特性,这个有什么新大陆发现呢,我们先看一个例子 以下内容要先有Lambda表达式基础,不清楚Lambda表达式的可以看这个 我们以下的例子都是基于这个学生类Student来操作,下面是学生类...
  • JDK8-Stream流常用方法

    千次阅读 2021-03-10 02:31:45
    Stream流的使用流操作是Java8提供一个重要新特性,它允许开发人员以声明性方式处理集合,其核心类库主要改进了对集合类的 API和新增Stream操作。Stream类中每一个方法都对应集合上的一种操作。将真正的函数式编程...
  • stream 的并发

    千次阅读 2018-09-03 13:57:45
    stream 的 各个方法使用如下:       package Test01; import java.util.ArrayList; import java.util.function.Predicate; import java.util.logging.Filter; /** * @auther Syntac...
  • jdk1.8中使用Stream流

    千次阅读 2019-06-06 20:40:30
    什么是Stream流 这里说明一下,Stream流不像传统的java.io中的inputStream和outputStream流,在jdk8中Stream是对集合Connection的增强,Stream比传统的流更加的精炼,语法更加的简洁。 我们为什么使用Stream流 Stream流...
  • 一文带你入门Java Stream流,太强了

    万次阅读 多人点赞 2020-04-01 09:51:55
    两个星期以前,就有读者强烈要求我写一篇 Java Stream 的文章,我说市面上不是已经有很多了吗,结果你猜他怎么说:“就想看你写的啊!”你看你看,多么苍白的喜欢啊。那就“勉为其难”写一篇吧,嘻嘻。 单从...
  • 文章目录Stream流1、Stream介绍2、Stream的操作stream().后的操作汇总1)创建流a、.stream()b、Arrays.stream()c、stream.ofd、无限流2)使用流abc3)终止Streamabc3、Stream的优势 Stream流 1、Stream介绍 ...
  • 常用函数式接口,Stream流

    千次阅读 2018-08-29 14:20:03
    06.第二章:Stream流_Stream流进行集合过滤的效果演示: 1).它不是IO流; 2).它是专门针对“集合”操作的一个流类,它类似于:迭代器。 只是它可以支持Lambda,使用更快捷的方式操作集合; 3).Stream流进行集合...
  • Java Stream流封装速度竟然如此给力!

    千次阅读 2020-11-24 22:49:36
    hello你好我是辰兮,很高兴你能来阅读,本篇文章是初识Java Stream流,先简单的聊一聊相关知识,应用场景,后续会陆续更新相关用法,分享获取新知,大家一起进步! 文章目录一、Stream序言二、Stream测试三、Stream...
  • Java8的Stream流详解

    万次阅读 多人点赞 2018-07-24 13:10:22
    首先,Stream流有一些特性: Stream流不是一种数据结构,不保存数据,它只是在原数据集上定义了一组操作。 这些操作是惰性的,即每当访问到流中的一个元素,才会在此元素上执行这一系列操作。 Stream不保存数据,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 386,667
精华内容 154,666
关键字:

stream流

友情链接: sanxiangnibain.zip