暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Stream

博博JAVA学习之路 2021-10-03
230

Stream



1.1.作用:

    针对集合操作,使用函数式编程方式结合Lambda表达式简化代码
    复制

    1.2.思想:

      Stream仅对数据进行加工,不存储数据,不是数据结构,是API
      复制


      1.3.定义:

        Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列
        复制

          Stream是Java8中处理集合的关键抽象概念,可以指定对集合的操作,
          可以执行复杂的查找、过滤和映射数据等操作。
          Stream API可以进行并行操作。
          Stream API提供了一种高效且易于使用的数据处理方式。
          复制

          1.4.操作对象:

            集合,数组,Stream
            复制

            1.5.Stream 和 Collection集合的区别:

              Collection是一种静态的内存数据结构,面向内存,存储在内存中。
              Stream是有关计算的,面向CPU,通过CPU实现计算。
              复制

              1.6.特点:

                不存储数据
                不改变源对象,返回一个持有结果的新Stream
                Stream操作是延迟执行,需要调用终止操作方法才会执行
                Stream只能操作一次(终止操作方法)
                复制


                1.7.操作步骤

                1.7.1.创建Stream

                  一个数据源(集合、数组),获取一个Stream
                  复制

                  1.7.2.中间操作

                    一个中间操作链,对数据源的数据进行处理
                    复制

                    1.7.3.终止操作

                      一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会再被使用
                      复制

                      1.8.Stream执行方式

                        串行:线程安全的,但是效率最低
                        并行:线程不安全,但是效率最高
                        复制

                        1.9.获取Stream方式

                          - 集合
                          - 数组
                          - 无限流
                          - Stream.of()
                          Stream.of()方法可以接收数组,并将其转换为Stream流。
                          - 将对象类型数组作为参数传递,会生成对象类型的Stream流
                          - 将基本类型数组作为参数传递,会生成基本类型数组的Stream流
                          例如:
                          Streams = Stream.of(String[] strs);
                              Streamns = Stream.of(int[] nums);
                          复制


                          1.9.5.代码

                            package com.bobo.study.jdk.stream;


                            import java.util.ArrayList;
                            import java.util.Arrays;
                            import java.util.HashSet;
                            import java.util.List;
                            import java.util.Set;
                            import java.util.UUID;
                            import java.util.stream.Stream;


                            import org.junit.Test;


                            public class StreamCreate {

                            @Test
                            public void testCreateStream() {
                            // 集合
                            // List
                            List<Integer> list = new ArrayList<Integer>();
                            list.parallelStream(); // 并行流
                            list.stream(); // 顺序流
                            // Set
                            Set<String> set = new HashSet<String>();
                            set.parallelStream(); // 并行流
                            set.stream(); // 顺序流
                            // Map没有Stream;

                            // 数组
                            String[] strs = new String[10];
                            Arrays.stream(strs);

                            // Stream.of() 通过参数生成,即将参数的类型统一后,生成Stream对象
                            Stream<Integer> intStream = Stream.of(1);
                            Stream<Object> objStream = Stream.of("1", "2", 3);

                            System.out.println(intStream);
                            System.out.println(objStream);

                            // Stream.iterate() 迭代生成, 参数一,迭代开始数值,参数二,如何迭代,输入输出类型一致
                            Stream<Integer> iterate = Stream.iterate(0, s -> s + 1);
                            // Stream.generate() 生成器,参数,生成器方法,可以使用随机生成方法生成数据
                            Stream<UUID> generate = Stream.generate(UUID::randomUUID);

                            iterate.limit(5).forEach(System.out::println);
                            generate.limit(5).forEach(System.out::println);

                            }


                            }


                            复制

                            结果:

                              java.util.stream.ReferencePipeline$Head@2d38eb89
                              java.util.stream.ReferencePipeline$Head@5fa7e7ff
                              0
                              1
                              2
                              3
                              4
                              59e3ee40-33b6-49a1-876f-99550ff2d8d5
                              8cb9b849-567e-42c2-9408-151acb99f22b
                              686da40c-16ee-4fa7-8f25-7fefc400129c
                              044387f5-ad74-454f-bd6e-b3caa647c3d5
                              4fdac61b-5158-4603-ac58-bcf4675cb7b2
                              复制


                              1.10.Stream中间操作

                              1.10.1.筛选与切片

                                filter(Predicate p)  -- 过滤元素
                                limit(int n) -- 截断流,使其元素个数不超过给定值
                                skip(int n) -- 跳过给定值的元素,若元素数量不够,则返回空数据
                                distinct() -- 筛选(去重),通过元素的hashCode()和equals()方法去重复元素
                                复制


                                1.10.1.5.代码

                                  package com.bobo.study.jdk.stream;


                                  import java.util.ArrayList;
                                  import java.util.List;


                                  import org.junit.Test;


                                  public class StreamFilter {

                                  @Test
                                  public void testStreamFilter() {
                                  List<Integer> list = new ArrayList<>();
                                  for(int i = 0; i < 10; i ++) {
                                  list.add(i);
                                  }

                                  list.stream().forEach(StreamFilter :: display);
                                  System.out.println("\n---- filter(s -> s > 0) -----------------------");

                                  // filter(Predicate p) 过滤
                                  list.stream().filter(s -> s > 0).forEach(StreamFilter :: display);

                                  System.out.println("\n---- limit(3) -----------------------");

                                  // limit(int n) 现在,只取n个元素
                                  list.stream().limit(3).forEach(StreamFilter :: display);

                                  System.out.println("\n---- limit(30) -----------------------");

                                  list.stream().limit(30).forEach(StreamFilter :: display);

                                  System.out.println("\n---- skip(5) -----------------------");

                                  // skip(int n) 跳过n个元素
                                  list.stream().skip(5).forEach(StreamFilter :: display);


                                  System.out.println("\n---- skip(50) -----------------------");

                                  list.stream().skip(50).forEach(StreamFilter :: display);

                                  System.out.println("\n---- distinct() -----------------------");

                                  // distinct() 去重
                                  list.add(1);
                                  list.stream().distinct().forEach(StreamFilter :: display);

                                  System.out.println("\n---------------------------");


                                  }

                                  public static void display(Object obj) {
                                  System.out.print(obj + ", ");
                                  }


                                  }


                                  复制


                                  结果:

                                    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
                                    ---- filter(s -> s > 0) -----------------------
                                    1, 2, 3, 4, 5, 6, 7, 8, 9,
                                    ---- limit(3) -----------------------
                                    0, 1, 2,
                                    ---- limit(30) -----------------------
                                    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                                    ---- skip(5) -----------------------
                                    5, 6, 7, 8, 9,
                                    ---- skip(50) -----------------------


                                    ---- distinct() -----------------------
                                    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                                    ---------------------------
                                    复制


                                    1.10.2.映射

                                      map(Function) -- 将元素映射为另一个类型的元素
                                      flatMap(Function<T, Stream>) -- 将元素映射为一个R 类型的元素
                                      复制

                                      对比

                                        参数类型
                                        - map参数为返回任意类型的Function对象
                                        - flatMap参数为返回值为Stream类型的Function对象
                                        返回类型
                                        map返回值可以是Stream<stream>对象
                                        - flatMap返回值必须是Stream对象,会返回传入的Stream对象进行拆分合并后的Stream对象
                                        复制

                                        1.10.2.4.代码

                                          package com.bobo.study.jdk.stream;


                                          import java.util.ArrayList;
                                          import java.util.Arrays;
                                          import java.util.List;
                                          import java.util.stream.IntStream;
                                          import java.util.stream.Stream;


                                          import org.junit.Test;


                                          public class StreamMap {

                                          @Test
                                          public void testStreamMap() {
                                          // map
                                          List<String> strList = Arrays.asList("aa", "bb", "cc", "dd");
                                          Stream<String> map1 = strList.stream().map(s -> s.toUpperCase());
                                          map1.forEach(StreamMap :: println);

                                          System.out.println("\n---------------------------");
                                          // map(Function<? super T, ? extends R> mapper)
                                          // map 方法是将传入进来的数据直接放到原Stream中,即可以Stream<Stream<T>>形式
                                          Stream<Stream<Character>> map2 = strList.stream().map(StreamMap :: strToStreamCharset);
                                          map2.forEach(StreamMap :: println);

                                          System.out.println("\n---------------------------");


                                          // flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
                                          // flatMap 方法是将传入进来的Stream流对象的数据拆分后,放到原Stream中,即Stream<T>形式
                                          Stream<Character> flatMap = strList.stream().flatMap(StreamMap :: strToStreamCharset);
                                          flatMap.forEach(StreamMap :: println);

                                          // map 与 flatMap 方法区别
                                          // map 方法参数无限制,可以是任意返回值的Function<T,R>对象
                                          // flatMap 方法参数必须是返回值为流对象的Function<T, Stream<R>>对象,即参数的返回值必须是Stream对象
                                          // map 返回的是任意数据类型,即返回Stream对象为Stream<R>对象,也可以是Stream<Stream<R>>对象
                                          // flatMap 由于返回的是Stream对象,所以可以将Stream对象数据进行拆分之后,合并一个Stream对象,即返回Stream对象为Stream<R>对象

                                          System.out.println("\n---------------------------");


                                          Stream<char[]> map3 = strList.stream().map(String :: toCharArray);
                                          map3.forEach(StreamMap :: println);

                                          System.out.println("\n---------------------------");

                                          strList = Arrays.asList("3", "1", "2","4");
                                          Stream<Integer> map4 = strList.stream().map(Integer::parseInt);
                                          map4.forEach(StreamMap :: println);

                                          System.out.println("\n---------------------------");

                                          IntStream mapToInt = strList.stream().mapToInt(Integer::parseInt);
                                          mapToInt.forEachOrdered(StreamMap :: println);

                                          System.out.println("\n---------------------------");

                                          }

                                          public static Stream<Character> strToStreamCharset(String str) {
                                          char[] charArray = str.toCharArray();
                                          List<Character> cs = new ArrayList<Character>();
                                          for (char c : charArray) {
                                          cs.add(c);
                                          }
                                          return cs.stream();
                                          }

                                          public static void println(Object obj) {
                                          System.out.print(obj + ", ");
                                          }

                                          }


                                          复制

                                          结果:

                                            AA, BB, CC, DD, 
                                            ---------------------------
                                            java.util.stream.ReferencePipeline$Head@379619aa,
                                            java.util.stream.ReferencePipeline$Head@cac736f,
                                            java.util.stream.ReferencePipeline$Head@5e265ba4,
                                            java.util.stream.ReferencePipeline$Head@156643d4,
                                            ---------------------------
                                            a, a, b, b, c, c, d, d,
                                            ---------------------------
                                            [C@182decdb, [C@26f0a63f, [C@4361bd48, [C@53bd815b,
                                            ---------------------------
                                            3, 1, 2, 4,
                                            ---------------------------
                                            3, 1, 2, 4,
                                            ---------------------------
                                            复制


                                            1.10.3.排序

                                              sorted() -- 自然排序
                                              sorted(Comparatorcomparator) -- 自定义排序规则
                                              复制


                                              1.10.3.3.代码

                                                package com.bobo.study.jdk.stream;


                                                import java.util.Arrays;
                                                import java.util.List;
                                                import java.util.stream.IntStream;
                                                import java.util.stream.Stream;


                                                import org.junit.Test;


                                                public class StreamSorted {

                                                @Test
                                                public void testStreamMap() {
                                                List<String> strList = Arrays.asList("3", "1", "2","4");
                                                Stream<Integer> map4 = strList.stream().map(Integer::parseInt);
                                                map4.forEach(StreamSorted :: println);

                                                System.out.println("\n---------------------------");
                                                // sorted() 自然排序,需要实现Comparable或者Comparator的对象
                                                IntStream mapToInt = strList.stream().mapToInt(Integer::parseInt).sorted();
                                                mapToInt.forEachOrdered(StreamSorted :: println);

                                                System.out.println("\n---------------------------");
                                                // sorted(Comparator<T> comparator) 自定义排序规则
                                                Stream<Integer> map = strList.stream().map(Integer :: parseInt);
                                                map.sorted((n1,n2) -> -Integer.compare(n1, n2)).forEach(StreamSorted :: println);
                                                }

                                                public static void println(Object obj) {
                                                System.out.print(obj + ", ");
                                                }

                                                }


                                                复制

                                                结果:

                                                  3, 1, 2, 4, 
                                                  ---------------------------
                                                  1, 2, 3, 4,
                                                  ---------------------------
                                                  4, 3, 2, 1,
                                                  复制

                                                  1.11.Stream终止操作

                                                  1.11.1.匹配与查找

                                                    allMatch(Predicatepredicate) -- 所有元素是否都匹配
                                                    anyMatch(Predicatepredicate) -- 元素是否有匹配的
                                                    noneMatch(Predicatepredicate) -- 是否没有此元素
                                                    findFirst() -- 第一个元素
                                                    findAny() -- 任意元素
                                                    count() -- 元素个数
                                                    max(Comparatorcomparator) -- 最大值
                                                    min(Comparatorcomparator) -- 最小值
                                                    forEach(Consumeraction) -- 内部遍历
                                                    复制


                                                    1.11.1.10.代码

                                                      package com.bobo.study.jdk.stream;


                                                      import java.util.Arrays;
                                                      import java.util.List;
                                                      import java.util.Optional;
                                                      import java.util.OptionalInt;
                                                      import java.util.stream.Stream;


                                                      import org.junit.Test;


                                                      public class StreamMatchAndFind {


                                                      @Test
                                                      public void testStreamMap() {
                                                      List<String> strList = Arrays.asList("3", "1", "2","4");


                                                      // 遍历元素
                                                      strList.stream().forEach(StreamMatchAndFind :: println);
                                                      System.out.println();

                                                      System.out.println("---------------------------");
                                                      // 所有元素是否都匹配
                                                      boolean allMatch = strList.stream().allMatch(s -> s.equals("2"));
                                                      System.out.println(allMatch);


                                                      System.out.println("---------------------------");
                                                      // 是否有匹配的元素
                                                      boolean anyMatch = strList.stream().anyMatch(s -> s.equalsIgnoreCase("2"));
                                                      System.out.println(anyMatch);


                                                      System.out.println("---------------------------");
                                                      // 是否没有此元素
                                                      boolean noneMatch = strList.stream().noneMatch(s -> s.equals("2"));
                                                      System.out.println(noneMatch);

                                                      System.out.println("---------------------------");
                                                      // 查找第一个元素
                                                      Optional<String> findFirst = strList.stream().findFirst();
                                                      System.out.println(findFirst);


                                                      System.out.println("---------------------------");
                                                      // 查找任意元素
                                                      Optional<String> findAny = strList.stream().findAny();
                                                      System.out.println(findAny);

                                                      System.out.println("---------------------------");
                                                      // 返回元素个数
                                                      long count = strList.stream().count();
                                                      System.out.println(count);


                                                      System.out.println("---------------------------");
                                                      // 返回元素最大值
                                                      Stream<Integer> map = strList.stream().map(Integer :: parseInt);
                                                      Optional<Integer> max = map.max(Integer :: compare);
                                                      System.out.println(max);


                                                      System.out.println("---------------------------");
                                                      // 返回元素最小值
                                                      OptionalInt min = strList.stream().mapToInt(Integer :: parseInt).min();
                                                      System.out.println(min);

                                                      }

                                                      public static void println(Object obj) {
                                                      System.out.print(obj + ", ");
                                                      }


                                                      }


                                                      复制

                                                      结果:

                                                        3, 1, 2, 4, 
                                                        ---------------------------
                                                        false
                                                        ---------------------------
                                                        true
                                                        ---------------------------
                                                        false
                                                        ---------------------------
                                                        Optional[3]
                                                        ---------------------------
                                                        Optional[3]
                                                        ---------------------------
                                                        4
                                                        ---------------------------
                                                        Optional[4]
                                                        ---------------------------
                                                        OptionalInt[1]
                                                        复制


                                                        1.11.2.归约

                                                          reduce() -- 将元素结合起来,例:求所有元素的和
                                                          复制


                                                          1.11.2.2.代码

                                                            package com.bobo.study.jdk.stream;


                                                            import java.util.Arrays;
                                                            import java.util.List;
                                                            import java.util.Optional;


                                                            import org.junit.Test;


                                                            public class StreamReduce {


                                                            @Test
                                                            public void testStreamMap() {
                                                            List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,0);

                                                            // 遍历元素
                                                            list.stream().forEach(StreamReduce :: println);
                                                            System.out.println();

                                                            System.out.println("---------------------------");
                                                            // 元素求和,初始值为20,再增加元素所有内容之后的求和
                                                            Integer reduce = list.stream().reduce(20, Integer :: sum);
                                                            System.out.println(reduce);
                                                            // 元素求和,返回Optional类型
                                                            Optional<Integer> reduce2 = list.stream().reduce(Integer :: sum);
                                                            System.out.println(reduce2);

                                                            }

                                                            public static void println(Object obj) {
                                                            System.out.print(obj + ", ");
                                                            }


                                                            }


                                                            复制


                                                            结果:

                                                              1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 
                                                              ---------------------------
                                                              65
                                                              Optional[45]


                                                              复制


                                                              1.11.3.收集

                                                                collect(Collector cr) -- 将流转换为其他形式,例:listset集合或数组
                                                                复制


                                                                1.11.3.2.代码

                                                                  package com.bobo.study.jdk.stream;


                                                                  import java.util.Arrays;
                                                                  import java.util.List;
                                                                  import java.util.Set;
                                                                  import java.util.stream.Collectors;


                                                                  import org.junit.Test;


                                                                  public class StreamCollect {


                                                                  @Test
                                                                  public void testStreamMap() {
                                                                  List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,0);

                                                                  System.out.println("---------------------------");
                                                                  // 转list
                                                                  List<Integer> collectList = list.stream().collect(Collectors.toList());
                                                                  System.out.println(collectList);
                                                                  // 转set
                                                                  Set<Integer> collectSet = list.stream().collect(Collectors.toSet());
                                                                  System.out.println(collectSet);
                                                                  // 转数组
                                                                  Integer[] array = list.stream().toArray(Integer[] :: new);
                                                                  System.out.println(Arrays.toString(array));
                                                                  }


                                                                  }


                                                                  复制

                                                                  结果:

                                                                    ---------------------------
                                                                    [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
                                                                    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                                                                    [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
                                                                    复制


                                                                    1.12.ParallelStream并行流

                                                                      -底层使用Fork/Join框架实现
                                                                      -无法保证元素顺序
                                                                      -使用线程同步,只能保证元素正确,不能保证元素顺序
                                                                      复制


                                                                      1.13.解决Stream并行线程不安全问题

                                                                        并行操作是线程不安全的
                                                                        方案一:使用同步代码快synchronized
                                                                        方案二:使用线程安全的集合
                                                                        方案三:使用collecttoArray方法
                                                                        复制


                                                                        1.13.5.代码

                                                                          package com.bobo.study.jdk.stream;


                                                                          import java.util.ArrayList;
                                                                          import java.util.Collections;
                                                                          import java.util.List;
                                                                          import java.util.Optional;
                                                                          import java.util.Vector;
                                                                          import java.util.stream.Collectors;


                                                                          import org.junit.Test;


                                                                          public class StreamParallel {


                                                                          @Test
                                                                          public void testParallel() {


                                                                          List<Integer> list = new ArrayList<Integer>();
                                                                          for (int i = 0; i < 10000; i ++) {
                                                                          list.add(i);
                                                                          }

                                                                          List<Integer> newList = new ArrayList<>();
                                                                          list.parallelStream().forEach(newList :: add);
                                                                          System.out.println("list1.size = " + newList.size());

                                                                          // 方案一: 使用synchronized同步代码快
                                                                          List<Integer> list1 = new ArrayList<>();
                                                                          list.parallelStream().forEach(n -> {
                                                                          synchronized (list1) {
                                                                          list1.add(n);
                                                                          }
                                                                          });
                                                                          System.out.println("list1.size = " + list1.size());

                                                                          // 方案二: 使用线程安全的集合
                                                                          Vector<Integer> v = new Vector<Integer>();
                                                                          list.parallelStream().forEach(v :: add);
                                                                          System.out.println("v.size = " + v.size());

                                                                          List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<Integer>());
                                                                          list.parallelStream().forEach(synchronizedList :: add);
                                                                          System.out.println("synchronizedList.size = " + synchronizedList.size());


                                                                          // 方案三: 使用collect/toarray操作
                                                                          List<Integer> collect = list.parallelStream().collect(Collectors.toList());
                                                                          System.out.println("collect.size = " + collect.size());

                                                                          Integer[] array = list.parallelStream().toArray(Integer[] :: new);
                                                                          System.out.println("array.length = " + array.length);

                                                                          }

                                                                          @Test
                                                                          public void testParallel1() {
                                                                          List<Integer> list = new ArrayList<Integer>();
                                                                          for(int i = 0; i < 10000; i ++) {
                                                                          list.add(i);
                                                                          }

                                                                          Optional<Integer> reduce = list.stream().reduce(Integer :: sum);

                                                                          System.out.println(reduce.get());

                                                                          Optional<Integer> reduce2 = list.parallelStream().reduce(Integer :: sum);
                                                                          System.out.println(reduce2.get());

                                                                          }




                                                                          }


                                                                          复制


                                                                          结果:

                                                                            49995000
                                                                            49995000
                                                                            list1.size = 5483
                                                                            list1.size = 10000
                                                                            v.size = 10000
                                                                            synchronizedList.size = 10000
                                                                            collect.size = 10000
                                                                            array.length = 10000
                                                                            复制


                                                                            2.Optional类

                                                                              用途:解决空指针异常问题
                                                                              复制


                                                                              3.Fork/Join框架

                                                                                JDK1.7推出的一套新的线程框架
                                                                                使用分治法、工作窃取算法
                                                                                复制
                                                                                文章转载自博博JAVA学习之路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                                                评论