• Java8中stream


    0.参考文档:

      Java Stream的API使用:https://www.cnblogs.com/jimoer/p/10995574.html

      Java8只stram:https://www.cnblogs.com/andywithu/p/7404101.html

      官网文档: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

    1.常用的知识库

      1.1  范式: 类名::方法名

             定义: 双冒号运算操作符是类方法的句柄,lambda表达式的一种简写,这种简写的学名叫eta-conversion或者叫η-conversion。

             说明:   

                  把 x -> System.out.println(x) 简化为 System.out::println 的过程称之为 eta-conversion

                  把 System.out::println 简化为 x -> System.out.println(x) 的过程称之为 eta-expansion

            案例:

    查看代码
    person -> person.getAge();
    可以替换成
    Person::getAge
    
    x -> System.out.println(x)
    可以替换成
    System.out::println
    out是一个PrintStream类的对象,println是该类的方法,依据x的类型来重载方法
    
    创建对象
    () -> new ArrayList<>();
    可以替换为
    ArrayList::new
    new关键字实际上调用的是ArrayList的构造方法

        1.2    Lambda表达式

                 语法 基本语法: (parameters) -> expression (parameters) ->{ statements; }

    2.初识stream

        总纲:

         

    Stream的特性:

    1.stream不存储数据

    2.stream不改变源数据

    3.stream的延迟执行特性
    特性说明:
            1.【使用步骤】使用一个Stream流,一般分为三个步骤:1. 获取数据源-> 2. 中间操作(Intermediate)-> 3. 终端操作(Terminal)。
            2.【操作分类】操作分为中间操作与终端操作
                       一个中间操作链,对数据源的数据进行处理,比如fifter、distinct、limit、skip、map、sorted。在一个流上执行终结操作之后,该流被消费,无法                再次被消费,比如:match、findFirst、count、max、min、forEach、reduce、collect。
               

    3.Stream 流的正常使用

          3.1创建流

    • 数组

      1. Arrays.stream(T array);
      2. stream.of(array)      
    • Collection

      1. Collection.stream()
      2. Collection.parallelStream()
    •    其他常用流

                  1. 空流:Stream.empty()

                  2. 无限数据流:Stream.generate()

                  3.规律的无限数流:Stream.iterate()

    查看代码
     @Test
    public void testArrayStream(){
        //1.通过Arrays.stream
        //1.1基本类型
        int[] arr = new int[]{1,2,34,5};
        IntStream intStream = Arrays.stream(arr);
        //1.2引用类型
        Student[] studentArr = new Student[]{new Student("s1",29),new Student("s2",27)};
        Stream<Student> studentStream = Arrays.stream(studentArr);
        //2.通过Stream.of
        Stream<Integer> stream1 = Stream.of(1,2,34,5,65);
        //注意生成的是int[]的流
        Stream<int[]> stream2 = Stream.of(arr,arr);
        stream2.forEach(System.out::println);
        //3.通过数组创建
         List<String> strs = Arrays.asList("11212","dfd","2323","dfhgf");
        //3.1创建普通流
          Stream<String> stream  = strs.stream();
         //3.2创建并行流
          Stream<String> stream1 = strs.parallelStream();
          //4.创建一个空的stream
          Stream<Integer> stream  = Stream.empty();
        //5.创建无限流,通过limit提取指定大小
           Stream.generate(()->"number"+new Random().nextInt()).limit(100).forEach(System.out::println);
          Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println);
        //6.产生规律的数据
        Stream.iterate(0,x->x+1).limit(10).forEach(System.out::println);
        Stream.iterate(0,x->x).limit(10).forEach(System.out::println);
        //Stream.iterate(0,x->x).limit(10).forEach(System.out::println);与如下代码意思是一样的
        Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);
    }

          3.2 对流的操作

             中间操作(中间操作链)

             流中间操作在应用到流上,返回一个新的流。下面列出了常用的流中间操作:

      • 【转换】map:通过一个 Function 把一个元素类型为 T 的流转换成元素类型为 R 的流。
      • 【转换合并】flatMap:通过一个 Function 把一个元素类型为 T 的流中的每个元素转换成一个元素类型为 R 的流,再把这些转换之后的流合并。
      • filter:过滤流中的元素,只保留满足由 Predicate 所指定的条件的元素。
      • distinct:使用 equals 方法来删除流中的重复元素。
      • limit:截断流使其最多只包含指定数量的元素。
      • skip:返回一个新的流,并跳过原始流中的前 N 个元素。
      • sorted:对流进行排序。
      • peek:返回的流与原始流相同。当原始流中的元素被消费时,会首先调用 peek 方法中指定的 Consumer 实现对元素进行处理。
      • dropWhile:从原始流起始位置开始删除满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。
      • takeWhile:从原始流起始位置开始保留满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。
      • concat :可以把两个stream合并成一个stream(合并的stream类型必须相同),只能两两合并

            终结操作(终结操作产生最终的结果)

      • max、min: 需要一下比较函数。
      • count:计数。
      • findFirst:查找第一个 。
      • findAny:对并行流十分有效,只要在任何片段发现了第一个匹配元素就会结束整个运算。
      • match:   匹配所有元素。
      • anyMatch:是否含有匹配元素。
      • forEach、  forEachOrdered 对流中的每个元素执行由 Consumer 给定的实现。在使用 forEach 时,并没有确定的处理元素的顺序;forEachOrdered 则按照流的相遇顺序来处理元素,如果流有确定的相遇顺序的话(这种方法保证了在顺序流和并行流中都按顺序执行。)。
      • reduce:进行递归计算。
      • collect:生成新的数据结构。    

          3.3并行流

      •  parallel():可以将普通顺序执行的流转变为并行流,只需要调用顺序流的parallel() 方法即可

          3.4原始类型流

      • Optional.of()创建指定值的Optional,聚合操作会返回一个Optional类型。 不能为空
      • Optional.ofNullable
      • orElse() optional 无论是否为null  都为被执行。
      • orElseGet() optional 为nulll 时被执行。
      • orElseThrow() 为空时直接抛异常。

          3.5 stream 类使用场景案例    

    查看代码
    @Test
        public void testStreamMap1() {
    
            //1.flatMap:拆解流
            String[] arr1 = {"a", "b", "c", "d"};
            String[] arr2 = {"e", "f", "c", "d"};
            String[] arr3 = {"h", "j", "c", "d"};
            // Stream.of(arr1, arr2, arr3).flatMap(x -> Arrays.stream(x)).forEach(System.out::println);
            //1.1 拆解流
            Stream.of(arr1, arr2, arr3).flatMap(Arrays::stream).forEach(System.out::println);
            //1.2 类型转换 map()
            Arrays.stream(arr1).map(o-> {
                return new Person(1,o ,12,"1年级");
            }).forEach(System.out::println);
            //2.比较函数 sort()
             //
              //2.1按照字符长度排序
                Arrays.stream(arr1).sorted((x,y)->{
                    if (x.length()>y.length())
                        return 1;
                    else if (x.length()<y.length())
                        return -1;
                    else
                        return 0;
                }).forEach(System.out::println);
              //2.2 倒序
            /**
             * 倒序
             * reversed(),java8泛型推导的问题,所以如果comparing里面是非方法引用的lambda表达式就没办法直接使用reversed()
             * Comparator.reverseOrder():也是用于翻转顺序,用于比较对象(Stream里面的类型必须是可比较的)
             * Comparator. naturalOrder():返回一个自然排序比较器,用于比较对象(Stream里面的类型必须是可比较的)
             */
            Arrays.stream(arr1).sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);
            Arrays.stream(arr1).sorted(Comparator.reverseOrder()).forEach(System.out::println);
            Arrays.stream(arr1).sorted(Comparator.naturalOrder()).forEach(System.out::println);
            //2.3 Comparator.comparing 现有的比较函数
            /**
             * thenComparing
             * 先按照首字母排序
             * 之后按照String的长度排序
             */
              Arrays.stream(arr1).sorted(Comparator.comparing(this::com1).thenComparing(String::length)).forEach(System.out::println);
              //3.forEach  遍历操作
                 //3.1  forEach在并行流中forEach不保证按顺序执行。
                    Stream.of("A","B","C", "D")
                    .parallel()
                    .forEach(e -> System.out.println(e));
                  //3.2 forEachOrdered  方法总是保证按顺序执行
                      Stream.of("A","B","C", "D")
                    .parallel()
                    .forEachOrdered(e -> System.out.println(e));
             // 4. reduce() 归约:(可以理解为递归,也是终止操作)
            List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
            //这里0是初始值,第一次执行规约应该是0+1,其中1是第一个值
            Integer sum = list.stream().reduce(0, (x,y) -> x + y);
            System.out.println("sum:"+sum);
             //计算累加值
            Optional<Integer> reduce = personList.stream().map(Person::getAge).reduce(Integer::sum);
            System.out.println("sum2:"+reduce.get());
             //5. collect  收集 :将流转换为其他形式,接收一个collection接口的实现,用于给stream元素做汇总的方法
            // 5.1 生成List
            List<Person>  personList1= personList.stream().collect(Collectors.toList());
            // 5.2 生成 set
            Set<Person>  personList2= personList.stream().collect(Collectors.toSet());
            //5.3 生成数组
            Person [] personList3= personList.stream().toArray(Person[]::new);
            //5.4 指定生成的类型
            HashSet<Person>  personList4= personList.stream().collect(Collectors.toCollection(HashSet::new));
            //5.5 统计 IntSummaryStatistics 统计分析类,其中的
            IntSummaryStatistics summaryStatistics = personList.stream().collect(Collectors.summarizingInt(Person::getAge));
            System.out.println("getAverage->"+summaryStatistics.getAverage());
            System.out.println("getMax->"+summaryStatistics.getMax());
            System.out.println("getMin->"+summaryStatistics.getMin());
            System.out.println("getCount->"+summaryStatistics.getCount());
            System.out.println("getSum->"+summaryStatistics.getSum());
            // Collectors.counting(), Collectors.averagingInt进行单次统计
            Long count = personList.stream().collect(Collectors.counting());
            Double avgAge = personList.stream().collect(Collectors.averagingInt(Person::getAge));
            //6 转换成为Map 分组和分片的意义是,将collect的结果集展示位Map<key,val>的形式
            //6.1 map 的类型转换
            Map<String,Integer> map = personList.stream().collect(Collectors.toMap(Person::getName,Person::getAge,(s,a)->s));
            //6.2 groupingBy 分组
            Map<String,List<Person>> map2 = personList.stream().collect(groupingBy(Person::getName));
            //6.3 partitioningBy 分类只有两类的结果
            Map<Boolean,List<Person>> map3= personList.stream().collect(partitioningBy(x->x.getAge()>9));
            //6.4 downstream指定类型
            Map<String,Set<Person>> map4 = personList.stream().collect(groupingBy(Person::getName,toSet()));
            //6.5 downstream 聚合操作
            Map<String,Long> map5 = personList.stream().collect(groupingBy(Person::getName,counting()));
            Map<String,Integer> map6 = personList.stream().collect(groupingBy(Person::getName,summingInt(Person::getAge)));
            Map<String,Optional<Person>> map7 = personList.stream().collect(groupingBy(Person::getName,maxBy(Comparator.comparing(Person::getAge))));
            //mapping收集器跟stream中间操作中的map基本上功能一致,进行属性转换并且按照指定的格式返回集合
            Map<String,Set<Integer>> map8 = personList.stream().collect(groupingBy(Person::getName,mapping(Person::getAge,toSet())));
            //6.6多级分组
            Map<String, Map<String, List<Person>>> collect = personList.stream().collect(Collectors.groupingBy(
                    Person::getGrade, Collectors.groupingBy(u -> {
                        if(((Person)u).getAge() <= 9) {
                            return "happy";
                        } else {
                            return "very happy";
                        }
                    })));
            //7.原始类型流 (在数据量比较大的情况下,将基本数据类型(int,double...)包装成相应对象流的做法是低效的)
            // 7.1  初始化 (IntStream,DoubleStream,LongStream) 目前是三种原始类型流
            DoubleStream  doubleStream = DoubleStream.of(0.1,0.2,0.3,0.8);
            IntStream intStream = IntStream.of(1,3,5,7,9);
            IntStream stream1 = IntStream.rangeClosed(0,100);
            IntStream stream2 = IntStream.range(0,100);
            //7.2 原始类型流转换与实际类型流之间的转换
            Stream<Double> stream = doubleStream.boxed();
            doubleStream = stream.mapToDouble(Double::new);
            //8.peek方法顾名思义,就是偷窥流内的数据 其中的 peek1,2,3 为Stream<T> peek(Consumer<? super T> action);
            Stream<Integer> streamPeek= Stream.iterate(1, x -> x + 1).limit(10).parallel();
    //        streamPeek.peek(this::peek1).filter(x -> x > 5)
    //                .peek(this::peek2).filter(x -> x < 8)
    //                .peek(this::peek3)
    //                .forEach(System.out::println);
            //9.Optional类型   聚合操作会返回一个Optional类型
            //9.1  Optional 创建, optional.get() 返回正常的值
            Optional<Person> studentOptional = Optional.of(personList.get(0));
            Optional<String> optionalStr = studentOptional.map(Person::getName);
            Optional<Double>  revert= studentOptional.get().getAge()== 0 ? Optional.empty() : Optional.of(1 / (double)studentOptional.get().getAge());
            //9.2 Optional默认值
            Integer[] arr = new Integer[]{4,5,6,7,8,9};
            Integer result = Stream.of(arr).filter(x->x>9).max(Comparator.naturalOrder()).orElse(-1);
            Integer result1 = Stream.of(arr).filter(x->x>9).max(Comparator.naturalOrder()).orElseGet(()->-1);
            Integer result2 = Stream.of(arr).filter(x->x>9).max(Comparator.naturalOrder()).orElseThrow(RuntimeException::new);
            //9.3 //ifPresent(Consumer<? super T> consumer)在结果部位空时进行消费操作
             String a= optionalStr.ifPresent(); 为空时,执行正常的操作。
            //10.流操作中判断是否为空的问题
    
        }

     为空判断:

        参考链接:https://www.cnblogs.com/zhangboyu/p/7580262.html

    查看代码
      //  1.null 是否能正常的装换成stream ,数组不能为空,为空编译器直接报错。集合转换成流,集合为空运行时报空指针。
            Integer[] arr=new Integer[]{4,5,6};
            List<Integer> strzint= Stream.of(arr).filter(o->o>6).collect(toList()); // 编译器直接报错
            Assert.assertNotNull(strzint);
            Stream<Person> personStream2= personList.stream().filter(o->o.getAge()>10);
            List<Person> personStream3=personStream2.collect(toList()); //执行之后不为NULL;size=0
            Assert.assertNotNull(personStream3);
            personList=null;
            Stream<Person> personStream= personList.stream().filter(o->o.getAge()>1); //NullPointerException
            List<Person> personStream1=personStream.collect(toList());
       // 2.optional 空对象的正常使用
            personList=null;
            //1.get(), 为空时不能直接进行调动。
            Optional<Person> emptyOpt = Optional.empty();
            emptyOpt.get(); //NoSuchElementException
            boolean bool=emptyOpt.isPresent();// 使用前验证是否为NUll值的判断。
            //2.of() 和 ofNullable() 方法创建包含值的 Optional。两个方法的不同之处在于如果你把 null 值作为参数传递进去,
            // of() 方法会抛出 NullPointerException:
            //对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法
            Optional<List<Person>> testOpt1 = Optional.of(personList); // NullPointerException
            Optional<List<Person>> testOpt2 = Optional.ofNullable(personList); //正常的调用情况
           //3.orElse(),orElseGet() 正常的使用状况
            //orElse() optional 无论是否为null  都为被执行,
            //orElseGet() optional 为nulll 时被执行。
            List<Person> result = Optional.ofNullable(personList).orElse(Init());
            List<Person> result2 = Optional.ofNullable(personList).orElseGet(() -> Init());
            personList=new ArrayList<>();
            List<Person> result3 = Optional.ofNullable(personList).orElse(Init());
            List<Person> result4 = Optional.ofNullable(personList).orElseGet(() -> Init());

    3.6 map 的使用

       

    查看代码
    
    public static void main(String[] args) {
     
    
      Map<String, String> map = new HashMap<String, String>();
      map.put("1", "value1");
      map.put("2", "value2");
      map.put("3", "value3");
      
      //第一种:普遍使用,二次取值
      System.out.println("通过Map.keySet遍历key和value:");
      for (String key : map.keySet()) {
       System.out.println("key= "+ key + " and value= " + map.get(key));
      }
      
      //第二种
      System.out.println("通过Map.entrySet使用iterator遍历key和value:");
      Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
      while (it.hasNext()) {
       Map.Entry<String, String> entry = it.next();
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
      
      //第三种:推荐,尤其是容量大时
      System.out.println("通过Map.entrySet遍历key和value");
      for (Map.Entry<String, String> entry : map.entrySet()) {
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
     
      //第四种
      System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
      for (String v : map.values()) {
       System.out.println("value= " + v);
      }
     }
  • 相关阅读:
    Docker常用命令
    Spark资源管理
    在Centos 7上安装Docker
    Docker网络管理
    Tensorflow 入门
    Spark远程调试函数
    Spark核心组件
    Spark job执行流程消息图
    数据库优化实践【性能检测工具篇】
    软件工程之系统建模篇【设计数据模型】
  • 原文地址:https://www.cnblogs.com/q994321263/p/15851231.html
Copyright © 2020-2023  润新知