H__D  

Stream API

  Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则 是 Stream API。

  • Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这 是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程 序员的生产力,让程序员写出高效率、干净、简洁的代码。

  • Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进 行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。 也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种 高效且易于使用的处理数据的方式。

为什么要使用Stream API

  • 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数 据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要 Java层面去处理。

  • Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据 结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中, 后者主要是面向 CPU,通过 CPU 实现计算。

什么是 Stream

  Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 “集合讲的是数据,Stream讲的是计算!”

  注意:

  1\Stream 自己不会存储元素。

  2\Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

  3\Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream 的操作三个步骤  

  1- 创建 :Stream 一个数据源(如:集合、数组),获取一个流

  2- 中间操作 :一个中间操作链,对数据源的数据进行处理

  3- 终止操作(终端操作) :一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

  

创建 Stream

 1 /**
 2  * 1. Stream关注的是对数据的运算,与CPU打交道
 3  *    集合关注的是数据的存储,与内存打交道
 4  *
 5  * 2.
 6  * ①Stream 自己不会存储元素。
 7  * ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
 8  * ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
 9  *
10  * 3.Stream 执行流程
11  * ① Stream的实例化
12  * ② 一系列的中间操作(过滤、映射、...)
13  * ③ 终止操作
14  *
15  * 4.说明:
16  * 4.1 一个中间操作链,对数据源的数据进行处理
17  * 4.2 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
18  *
19  *
20  *  测试Stream的实例化
21  *
22  */
23 public class StreamAPITest {
24 
25     //创建 Stream方式一:通过集合
26     @Test
27     public void test1(){
28         List<Employee> employees = EmployeeData.getEmployees();
29 
30 //        default Stream<E> stream() : 返回一个顺序流
31         Stream<Employee> stream = employees.stream();
32 
33 //        default Stream<E> parallelStream() : 返回一个并行流
34         Stream<Employee> parallelStream = employees.parallelStream();
35     }
36 
37     //创建 Stream方式二:通过数组
38     @Test
39     public void test2(){
40         int[] arr = new int[]{1, 2, 3, 4, 5, 6};
41         //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
42         IntStream stream = Arrays.stream(arr);
43         
44         Employee e1 = new Employee(1001, "Tom");
45         Employee e2 = new Employee(1002, "Jerry");
46         Employee[] arr1 = new Employee[]{e1, e2};
47         Stream<Employee> stream1 = Arrays.stream(arr1);
48     }
49 
50     //创建 Stream方式三:通过Stream的of()
51     @Test
52     public void test3(){
53         Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
54     }
55 
56     //创建 Stream方式四:创建无限流
57     @Test
58     public void test4(){
59         //      迭代
60 //      public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
61         //遍历前10个偶数
62         Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
63 
64         //      生成
65 //      public static<T> Stream<T> generate(Supplier<T> s)
66         Stream.generate(Math::random).limit(10).forEach(System.out::println);
67 
68     }
69 }

Stream 的中间操作

  多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止 操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全 部处理,称为“惰性求值”。

   

  

  

 1 /**
 2  * 测试Stream的中间操作
 3  */
 4 public class StreamAPITest1 {
 5     //1-筛选与切片
 6     @Test
 7     public void test1() {
 8         List<Employee> list = EmployeeData.getEmployees();
 9 //        filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
10         list.stream().filter(e -> e.getSalary() > 7000).forEach(System.out::println);
11 
12         System.out.println();
13 //        limit(n)——截断流,使其元素不超过给定数量。
14         list.stream().limit(3).forEach(System.out::println);
15 
16         System.out.println();
17 //        skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
18         list.stream().skip(5).forEach(System.out::println);
19 
20         System.out.println();
21 //        distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
22         list.add(new Employee(1010, "刘强东", 40, 8000));
23         list.add(new Employee(1010, "刘强东", 41, 8000));
24         list.add(new Employee(1010, "刘强东", 40, 8000));
25         list.add(new Employee(1010, "刘强东", 40, 8000));
26         list.add(new Employee(1010, "刘强东", 40, 8000));
27         list.stream().distinct().forEach(System.out::println);
28 
29 
30     }
31 
32 
33     //映射
34     @Test
35     public void test2() {
36 //        map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
37         List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
38         list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
39 
40 //        练习1:获取员工姓名长度大于3的员工的姓名。
41         List<Employee> employees = EmployeeData.getEmployees();
42         Stream<String> namesStream = employees.stream().map(Employee::getName);
43         namesStream.filter(name -> name.length() > 3).forEach(System.out::println);
44 
45         //练习2:
46         Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringtoStream);
47         streamStream.forEach(s -> s.forEach(System.out::println));
48         System.out.println();
49 //        flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
50         Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringtoStream);
51         characterStream.forEach(System.out::println);
52     }
53 
54     //将字符串中的多个字符构成的集合转换为对应的Stream的实例
55     public static Stream<Character> fromStringtoStream(String str) {
56         ArrayList<Character> list = new ArrayList<>();
57         for (Character c : str.toCharArray()) {
58             list.add(c);
59         }
60         return list.stream();
61     }
62 
63     //3-排序
64     @Test
65     public void test3() {
66 //        sorted()——自然排序
67         List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
68         list.stream().sorted().forEach(System.out::println);
69         //抛异常,原因:Employee没有实现Comparable接口
70 //        List<Employee> employees = EmployeeData.getEmployees();
71 //        employees.stream().sorted().forEach(System.out::println);
72 
73 //        sorted(Comparator com)——定制排序
74         List<Employee> employees = EmployeeData.getEmployees();
75         employees.stream().sorted((e1, e2) -> {
76             int ageValue = Integer.compare(e1.getAge(), e2.getAge());
77             if (ageValue != 0) {
78                 return ageValue;
79             } else {
80                 return Double.compare(e1.getSalary(), e2.getSalary());
81             }
82         }).forEach(System.out::println);
83     }
84 }

Stream 的终止操作

  终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例 如:List、Integer,甚至是 void 。

  流进行了终止操作后,不能再次使用。

   

  

  

  

 1 /**
 2  * 测试Stream的终止操作
 3  *
 4  */
 5 public class StreamAPITest2 {
 6     //1-匹配与查找
 7     @Test
 8     public void test1(){
 9         List<Employee> employees = EmployeeData.getEmployees();
10 
11 //        allMatch(Predicate p)——检查是否匹配所有元素。
12 //          练习:是否所有的员工的年龄都大于18
13         boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
14         System.out.println(allMatch);
15 
16 //        anyMatch(Predicate p)——检查是否至少匹配一个元素。
17 //         练习:是否存在员工的工资大于 10000
18         boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);
19         System.out.println(anyMatch);
20 
21 //        noneMatch(Predicate p)——检查是否没有匹配的元素。
22 //          练习:是否存在员工姓“雷”
23         boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
24         System.out.println(noneMatch);
25 
26 //        findFirst——返回第一个元素
27         Optional<Employee> first = employees.stream().findFirst();
28         System.out.println(first);
29 
30 //        findAny——返回当前流中的任意元素
31         Optional<Employee> any = employees.parallelStream().findAny();
32         System.out.println(any);
33     }
34 
35     @Test
36     public void test2(){
37         List<Employee> employees = EmployeeData.getEmployees();
38 
39         // count——返回流中元素的总个数
40         long count = employees.stream().count();
41         System.out.println(count);
42 
43 //        max(Comparator c)——返回流中最大值
44 //        练习:返回最高的工资:
45         Stream<Double> salaryStream = employees.stream().map(employee -> employee.getSalary());
46         Optional<Double> max = salaryStream.max(Double::compareTo);
47         System.out.println(max);
48 
49 //        min(Comparator c)——返回流中最小值
50 //        练习:返回最低工资的员工
51         Optional<Employee> min = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
52         System.out.println(min);
53         System.out.println();
54 
55 
56 //        forEach(Consumer c)——内部迭代
57         employees.stream().forEach(System.out::println);
58         System.out.println();
59 
60         //使用集合的遍历操作
61         employees.forEach(System.out::println);
62     }
63 
64     //2-归约
65     @Test
66     public void test3(){
67 
68 //        reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
69 //        练习1:计算1-10的自然数的和
70         List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
71         Integer sum = list.stream().reduce(0, Integer::sum);
72         System.out.println(sum);
73 
74 //        reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
75 //        练习2:计算公司所有员工工资的总和
76         List<Employee> employees = EmployeeData.getEmployees();
77         Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
78         Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
79         System.out.println(sumMoney);
80     }
81 
82     //3-收集
83     @Test
84     public void test4() {
85 //        collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
86 //        练习1:查找工资大于6000的员工,结果返回为一个List或Set
87 
88         List<Employee> employees = EmployeeData.getEmployees();
89         List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
90         employeeList.forEach(System.out::println);
91         System.out.println();
92 
93         Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
94         employeeSet.forEach(System.out::println);
95     }
96 }

Optional类

  • Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

  • 创建Optional类对象的方法:

    • Optional.of(T t) : 创建一个 Optional 实例,t必须非空;  
    • Optional.empty() : 创建一个空的 Optional 实例
    • Optional.ofNullable(T t):t可以为null
  • 判断Optional容器中是否包含对象:

    • boolean isPresent() : 判断是否包含对象

    • void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。

  • 获取Optional容器的对象:
    • T get(): 如果调用对象包含值,返回该值,否则抛异常

    • T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。

    • T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由

      Supplier接口实现提供的对象。

    • T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。

Option类代码举例

 1 public class Boy {
 2     private Girl girl;
 3 
 4     @Override
 5     public String toString() {
 6         return "Boy{" +
 7                 "girl=" + girl +
 8                 '}';
 9     }
10 
11     public Girl getGirl() {
12         return girl;
13     }
14 
15     public void setGirl(Girl girl) {
16         this.girl = girl;
17     }
18 
19     public Boy() {
20 
21     }
22 
23     public Boy(Girl girl) {
24 
25         this.girl = girl;
26     }
27 }
Boy.java
 1 public class Girl {
 2 
 3     private String name;
 4 
 5     @Override
 6     public String toString() {
 7         return "Girl{" +
 8                 "name='" + name + '\'' +
 9                 '}';
10     }
11 
12     public String getName() {
13         return name;
14     }
15 
16     public void setName(String name) {
17         this.name = name;
18     }
19 
20     public Girl() {
21 
22     }
23 
24     public Girl(String name) {
25 
26         this.name = name;
27     }
28 }
Girl.java
  1 /**
  2  * Optional类:为了在程序中避免出现空指针异常而创建的。
  3  *
  4  * 常用的方法:ofNullable(T t)
  5  *            orElse(T t)
  6  *
  7  */
  8 public class OptionalTest {
  9 
 10 /*
 11 Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
 12 Optional.empty() : 创建一个空的 Optional 实例
 13 Optional.ofNullable(T t):t可以为null
 14 
 15  */
 16     @Test
 17     public void test1(){
 18         Girl girl = new Girl();
 19 //        girl = null;
 20         //of(T t):保证t是非空的
 21         Optional<Girl> optionalGirl = Optional.of(girl);
 22 
 23         System.out.println(optionalGirl.get());
 24     }
 25 
 26     @Test
 27     public void test2(){
 28         Girl girl = new Girl();
 29 //        girl = null;
 30         //ofNullable(T t):t可以为null
 31         Optional<Girl> optionalGirl = Optional.ofNullable(girl);
 32         System.out.println(optionalGirl);
 33         //orElse(T t1):如果单前的Optional内部封装的t是非空的,则返回内部的t.
 34         //如果内部的t是空的,则返回orElse()方法中的参数t1.
 35         Girl girl1 = optionalGirl.orElse(new Girl("赵丽颖"));
 36         System.out.println(girl1);
 37 
 38     }
 39 
 40 
 41     public String getGirlName(Boy boy){
 42         return boy.getGirl().getName();
 43     }
 44 
 45     @Test
 46     public void test3(){
 47         Boy boy = new Boy();
 48         boy = null;
 49         String girlName = getGirlName(boy);
 50         System.out.println(girlName);
 51 
 52     }
 53     //优化以后的getGirlName():
 54     public String getGirlName1(Boy boy){
 55         if(boy != null){
 56             Girl girl = boy.getGirl();
 57             if(girl != null){
 58                 return girl.getName();
 59             }
 60         }
 61 
 62         return null;
 63 
 64     }
 65 
 66     @Test
 67     public void test4(){
 68         Boy boy = new Boy();
 69         boy = null;
 70         String girlName = getGirlName1(boy);
 71         System.out.println(girlName);
 72 
 73     }
 74 
 75     //使用Optional类的getGirlName():
 76     public String getGirlName2(Boy boy){
 77 
 78         Optional<Boy> boyOptional = Optional.ofNullable(boy);
 79         //此时的boy1一定非空
 80         Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
 81 
 82         Girl girl = boy1.getGirl();
 83 
 84         Optional<Girl> girlOptional = Optional.ofNullable(girl);
 85         //girl1一定非空
 86         Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
 87 
 88         return girl1.getName();
 89     }
 90 
 91     @Test
 92     public void test5(){
 93         Boy boy = null;
 94         boy = new Boy();
 95         boy = new Boy(new Girl("苍老师"));
 96         String girlName = getGirlName2(boy);
 97         System.out.println(girlName);
 98 
 99     }
100 
101 
102 
103 }

 

 

 

posted on 2021-02-26 23:06  H__D  阅读(19)  评论(0编辑  收藏