函数编程:强大的 Stream API
函数编程:强大的 Stream API
每博一文案
只要有人的地方,世界就不会是冰冷的,我们可以平凡,但绝对不可以平庸。
—————— 《平凡的世界》
人活着,就得随时准备经受磨难。他已经看过一些书,知道不论是普通人还是了不起的人,
都要在自己的一生中经历许多磨难。磨难使人坚强。
—————— 《平凡的世界》
hellip... 人哪,活着是这么的苦,一旦你从幸福的彼岸被抛到苦难的此岸,你真
是处处走投无路,而现在你才知道,在天堂与地狱之间原来也只有一步之遥。
——————《平凡的世界》
@
1. Stream 的概述
- Java8 中有两大最为重要的改变。第一个便是 Lambda 表达式,想要进一步了解的大家可以移步至 🔜🔜🔜 函数式编程:Lambda 表达式_ChinaRainbowSea的博客-CSDN博客
;另外一个则为是我们这个主题了:Stream API 了。
- Stream API 是在
java.util.stream
包下的,Stream 是把真正的函数式编程 风格引入到 Java 中,这时目前为止对 java 类库最好的补充了,因为 Stream API 可以极大的提供 Java程序员的生产力,让程序员写出更高效率,干净,简洁的代码。 - Stream 是 java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找,过滤和映射数据等操作,使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询 也可以使用 Stream API 的来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
1.1 为什么要使用Stream API
在实际开发种,项目中多数据源都是来自于 MySQ,Oracle 等数据库的,但现在数据源可以更多了,有 MongDB,Radis 等,而这些 NoSQL 的数据就需要 Java层面去处理。
1.2 什么是 Stream
是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列,“集合讲的是数据,Stream 讲的是计算” 。
注意:
- Stream 自己不会存储元素。
- Stream 不会改变源对象,相反,他们会返回一个持有结果的新 Stream 。这一点和 String 不可变的特点类似。
- Stream 操作是延迟执行的。这意味着它们会等到需要结果的时候才执行。
1.3 Stream 的操作三个步骤
- 创建 Stream
一个数据源(如:集合,数组),获取一个流
2.中间操作
一个中间操作链,对数据源的数据进行处理。
3. 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会再被使用(也不可再使用)。
1.4 Stream 与 Colliection 的区别
Stream 和以前的Collection操作不同, Stream操作还有两个基础的特征:
-
Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道。 这样做可以对操作进行优化, 比如延迟执行.
-
内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
- 当使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。
- Stream 和 Collection 集合的主要区别:Collection 是一种静态的内存数据结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中后者是主要是面向 CPU 。通过 CPU 实现计算的。
2. 创建 Stream 的四种方式
因为 Stream 是一个接口,所以我们无法通过 new 的方式创建该对象。
2.1 创建Stream 方式一:通过集合
Java8 中的 Collection 接口被扩展,提供了两个获取流 的方法:
-
default Stream stream() : 返回一个顺序流
-
default Stream parallelStream() : 返回一个并行流
package blogs.blog13;
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest {
public static void main(String[] args) {
List<Employee> employeeList = EmployeeData.getEmployees();
//default Stream<E> stream(): 返回一个顺序流
Stream<Employee> stream = employeeList.stream();
System.out.println(stream);
// default Stream<E> parallelStream : 返回一个并行流
Stream<Employee> employeeStream = employeeList.parallelStream();
System.out.println(employeeStream);
}
}
2.2 创建 Stream 方式二:通过数组
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
- static Stream stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
-
public static IntStream stream(int[] array)
-
public static LongStream stream(long[] array)
-
public static DoubleStream stream(double[] array)
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamAPITest {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,6};
// 调用 Arrays 类中的 static<T> stream(T[] array)返回一个对象
IntStream stream = Arrays.stream(arr);
System.out.println(stream);
}
}
2.3 创建 Stream 的方式三: 通过 Stream 的 of()
可以调用Stream类静态方法 of(), 通过显示值创建一个流。它可以接收任意数量的参数。
- public static Stream of(T... values) : 返回一个流
import java.util.stream.Stream;
public class StreamAPITest {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
System.out.println(stream);
}
}
2.4 创建 Stream 方式四: 创建无限流
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
- 迭代
public static Stream iterate(final T seed, final UnaryOperator f)
- 生成
public static Stream generate(Supplier s)
import java.util.stream.Stream;
public class StreamAPITest {
public static void main(String[] args) {
// 迭代:
//public static<T> Stream<T> inerate(final T seed,final UnaryOperator<T> f)
// 遍历前 10 个偶数
Stream.iterate(0,t->t+2).forEach(System.out::println);
// 生成:
// public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
}
3. Stream 的中间操作
多个中间操作可以连接起来形成一个 流水线 ,除非流水线上触发终止操作,否则中间操作不会执行任何的处理! ,而终止操作时一次性全处理。 这样的 称为 惰性求值 。
3.1 筛选与切片
如下是关于 Stream 中间操作筛选与切片的一些常用的方法
- Stream
filter(Predicate<? super T> predicate); // 接收 Lambda 表达式,从流中排除某些元素
package blogs.blog13;
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
// 创建一个 Stream 对象
Stream<Employee> stream = list.stream();
// 使用 filter 进行一个筛选
// boolean test(T t)
// 筛选出:工资大于 7000 的 Employee 对象
stream.filter(e->e.getSalary() > 7000).forEach(System.out::println);
}
}
注意: stream 和集合中的迭代器是一样的,不可多次不同结构的使用。 再次使用时需要新建一个 stream 对象,才能使用。简单的来说:就是 stream 对象一次只能对应一次操作,再进行一个新的操作时,必须新建一个 stream 对象才行。不然报java.lang.IllegalStateException
异常。
- Stream
distinct(); // 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
注意: 使用该方法,因为涉及到筛选,需要对元素数据进行一个比较判断,所以和集合同理:我们必须重写其元素的 hashCode() 和 equals() 方法,不然报异常;
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
List<Employee> list = new ArrayList<Employee>();
// distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
// 所以对应存储的 Employee 对象需要重写 hashCode() 和 equals()方法
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",20,8000));
list.stream().distinct().forEach(System.out::println);
}
}
- Stream
limit(long maxSize); // 截断流,使其元素不超过给定数量
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
// 创建一个 Stream 对象
Stream<Employee> stream = list.stream();
// limit(n) 截断流: 筛选出 list 集合中存储的前3 个信息
stream.limit(3).forEach(System.out::println);
}
}
- Stream
skip(long n); // 跳过元素,返回一个扔掉了前 n 个元素的流,若流中元素不足 n 个,则返回一个空流,与 limit(n) 互补。
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
// skip(n) 跳过元素,返回一个扔掉了前 n 个元素的流,若流中元素不足 n 个,则返回一个 空
// stream 不可二次使用,需要新建
Stream<Employee> skip = list.stream().skip(3);
skip.forEach(System.out::println); // 该操作是终止操作,并运用了方法引用
}
}
3.2 映射
Stream 注意: 返回的是一个新的对象,不会修改原本的数据信息的。map(Function<? super T,? extends R> mapper) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
List<String> list = Arrays.asList("aa","bb","cc");
// 创建一个 Stream 对象
Stream<String> stream = list.stream();
Stream<String> stringStream = stream.map(s -> s.toUpperCase()); // toUpperCase() 将字母转换为大写的
stringStream.forEach(System.out::println); // Stream 终止操作
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
// 将字符串的多个字符构造的从集合转换为单个字符串并存储到 List 集合中
public static Stream<Character> fromStringToStream(String str) {
ArrayList<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) { // toCharArray()将一个字符串拆分为单个字符
list.add(character);
}
return list.stream();
}
public static void main(String[] args) {
// flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的
// 数据组成一个数据
List<String> list = Arrays.asList("aa","AA","bb");
Stream<String> stream = list.stream();
Stream<Character> characterStream = stream.flatMap(StreamAPITest02::fromStringToStream); // 方法引用
characterStream.forEach(System.out::println);
}
}
举例: 练习:获取员工姓名长度大于 3 的员工的姓名:
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
List<Employee> employees = EmployeeData.getEmployees();
// 创建 stream 对象
Stream<Employee> stream = employees.stream();
// 获取到一个关于 Employee 对象中的 有关 name 属性的 Stream 对象
Stream<String> stringStream = stream.map(e -> e.getName());
// 获取到该 Stream 对象中 name 长度大于 3 的名字
Stream<String> stringFilter = stringStream.filter(e -> e.length() > 3);
stringFilter.forEach(System.out::println);
}
}
3.3 排序
- Stream
sorted() 产生一个新流,其中按自然顺序排序 - Stream
sorted(Comparator<? super T> comparator) 产生一个新流,其中按比较器顺序排序(也就是定制排序)。
注意:这里的排序要排序的元素信息,必须实现 Comparable 接口或者是 Comparator 定制排序 ,不然报异常,关于这部分排序内容,想要多加了解的,可以移步至:🔜🔜🔜 比较器: Comparable 与 Comparator 区别_ChinaRainbowSea的博客-CSDN博客
举例:soreted() 运用自然排序 ,排序的元素实现了 comparable 接口
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
// sorted -- 自然排序
// 注意排序:需要实现 Comparable 接口
// 注意泛型不能放基本数据类型
List<Integer> list = Arrays.asList(12,56,3,2,1);
// 创建 Stream 对象
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println);
}
}
举例: sorted(comparator com ) 定制排序 通过年龄排序,默认是升序的 > 0 返回 1
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest02 {
public static void main(String[] args) {
// sorted(comparator com ) 定制排序 通过年龄排序,默认是升序的 > 0 返回 1,
List<Employee> employees = EmployeeData.getEmployees();
// 创建 Stream 对象
Stream<Employee> stream = employees.stream();
Stream<Employee> sorted = stream.sorted((e1, e2) -> {
int compare = Integer.compare(e1.getAge(), e2.getAge()); // 年龄排序
if (compare != 0) {
return compare;
} else { // 年龄一致,再通过比较器进一步排序,比较薪资排序
return Double.compare(e1.getSalary(), e2.getSalary());
}
});
sorted.forEach(System.out::println);
}
}
4. Stream 的终止操作
终端操作会从流水线 生成的结果。其结果可以是任何不是流的值,例如:list,Integer,甚至是 void
注意: Stream 流一旦执行了终止操作后,就不能再使用了。
4.1 匹配与查找
- allmathc()检查Stream 流中内容中是否匹配所有元素
boolean allMatch(Predicate<? super T> predicate); // 检查是否匹配所有元素
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
public class StreamAPITest03 {
/**
* allMatch(Predicate p) 检查是否匹配所有元素。
* 练习:是否所有的员工的年龄都大于 18
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
boolean b = list.stream().anyMatch(e -> e.getAge() > 18);
System.out.println(b);
}
}
- anyMatch(Predicate p) 检查 Stream 流中内容中是否至少匹配一个元素。
boolean anyMatch(Predicate<? super T> predicate);
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
public class StreamAPITest03 {
/**
* anyMath(Predicate p) 检查是否至少匹配一个元素:
* 练习: 是否存在元素的工资大于 10000
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
boolean b = list.stream().anyMatch(e -> e.getSalary() > 1000);
System.out.println(b);
}
}
- noneMatch(Predicate p) 检查Stream 流中内容中是否没有匹配所有元素
boolean noneMatch(Predicate<? super T> predicate);
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* noneMatch(Predicate p) 检查是否没有匹配的元素。
* 练习: 是否存在员工姓 "雷"
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
// String 中的startsWith 表示该字符串中是否含有该字符内容,有返回 true,没有返回 fasle
boolean b = stream.noneMatch(e -> e.getName().startsWith("雷"));
System.out.println(b);
}
}
- findFirst() 返回Stream 流中内容的第一个元素
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* findFirst 返回第一个元素
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
Optional<Employee> first = stream.findFirst();
System.out.println(first);
}
}
- findAny() 返回当前Stream 流中内容中中任意元素
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* findAny 返回当前流中的任意元素
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
Optional<Employee> any = stream.findAny();
System.out.println(any);
}
}
- count() 返回Stream 流中内容中中元素总数
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* count 返回流中元素的总个数
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
long count = stream.count();
System.out.println(count);
}
}
- max(Comparator c) 返回Stream 流中内容中中最大值
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* max(Comparator c) 返回流中最大值
* 练习返回最高的工资。
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
// 创建一个有关于 Employee 对象的 属性为salary的 Stream 流
Stream<Double> doubleSalary = stream.map(e -> e.getSalary());
Optional<Double> max = doubleSalary.max(Double::compareTo);// 方法引用
System.out.println(max);
}
}
- min(Comparator c) 返回Stream 流中内容中中最小值
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* max(Comparator c) 返回流中最大值
* 练习返回最低的工资。
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
// 创建一个有关于 Employee 对象的 属性为salary的 Stream 流
Stream<Double> doubleSalary = stream.map(e -> e.getSalary());
Optional<Double> min = doubleSalary.min(Double::compareTo);// 方法引用
System.out.println(min);
}
}
- forEach(Consumer c) 内部迭代(使用 Collection ) 接口需要用户去做迭代,称为 外部迭代。相反 ,Stream API 使用内部迭代—— 它帮你把迭代做了
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
list.stream().forEach(System.out::println);
System.out.println("****************************");
// 集合的遍历操作
list.forEach(System.out::println);
}
}
4.2 归约
如下是关于归约常用方法:
- reduce(BinaryOperator b) 可以将流中元素结合起来,比如: sum,count 得到一个值。返回 Optional
Optional<T> reduce(BinaryOperator<T> accumulator); //
- reduce(T iden,BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
T reduce(T identity, BinaryOperator<T> accumulator); //
补充: map 和 reduce 的连接通常为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。
举例:
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* reduce(T identity, BinaryOperator ) 可以将流中元素反复结合起来,得到一个值。返回
* 练习: 计算 1-10 的自然数的和
*/
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream = list.stream();
Integer reduce = stream.reduce(0, Integer::sum);
System.out.println(reduce);
}
}
举例:
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* reduce(BinaryOperator) 可以将流中元素反复的结合起来,得到一个值,返回Optional<T>
* 练习: 计算公司所有员工的工资的总和
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
// 获取到 Employees 员工工资的 Stream 流对象
Stream<Double> streamSalary = list.stream().map(e -> e.getSalary());
Optional<Double> reduce = streamSalary.reduce((d1, d2) -> d1 + d2);
System.out.println(reduce);
}
}
4.3 收集
Collect(Collectior c) : 将流转换为其他形式,接收一个 Collector 接口的实现,用于 Stream 中元素做汇总的方法。
<R,A> R collect(Collector<? super T,A,R> collector);
Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List ,Set,Map)。另外,Collectior 实用类提供了很多静态方法,可以方便创建常见收集器实例。具体方法与实例如下表:
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamAPITest03 {
/**
* collect(Collector c) 将流转换为其他形式,接收一个Collector 接口的实现,
* 用于给 Stream 中
* 练习1 查找工资大于 6000 的员工,结果返回为一个 List 或 set
*/
public static void main(String[] args) {
List<Employee> list = EmployeeData.getEmployees();
// 获取到一个工资大于 6000 的 Stream 流
Stream<Employee> employeeStream = list.stream().filter(e->e.getSalary() > 6000);
List<Employee> collect = employeeStream.collect(Collectors.toList());
collect.forEach(System.out::println);
}
}
5.1 Optional类
到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代 码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。
-
Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不 存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
-
Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在 则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional提供很多有用的方法,这样我们就不用显式进行空值检测
5.2 创建 Optional 的三种方式
创建Optional类对象的方法:
- Optional.of(T t) : 创建一个 Optional 实例,t 必须非空。
- Optional.empty() : 创建一个空的 Optional 实例。
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<Girl> optional = Optional.empty();
System.out.println(optional);
}
}
- Optional.ofNullable(T t): t 可以为null。
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Girl girl = new Girl();
girl = null;
Optional<Girl> optional = Optional.ofNullable(girl); // ofNullable 中的 t 参数可以为空
System.out.println(optional);
}
}
5.3 Optional 类中其他常用的方法
判断Optional容器中是否包含对象:
-
boolean isPresent() : 判断是否包含对象
-
void ifPresent(Consumer consumer) : 如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
获取Optional容器的对象:
-
T get(): 如果调用对象包含值,返回该值,否则抛异常
-
T orElse(T other) : 如果有值则将其返回,否则返回指定的other对象。
-
T orElseGet(Supplier other) : 如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
-
T orElseThrow(Supplier exceptionSupplier) : 如果有值则将其返 回,否则抛出由Supplier接口实现提供的异常。
import java.util.Optional;
public class OptionalTest {
// orElse(T t) 如果单前的 Optional 内部封装的t是非空的,则返回内部的 t,
// 如果内部的 t是空的,则返回orElse()方法中的参数t1.
// 使用 Optional 类的 getGirName()
public static String getGirName2(Girl girl) {
Optional<Girl> optional = Optional.ofNullable(girl);
// 如果 Optional 中的 girl 为 null ,则使用 如下的 new Girl(new Boy("肖战")) 替换就不为空了
// 不为 null 是不会发生替换的,使用原来的就可以了。
Girl girl2 = optional.orElse(new Girl(new Boy("肖战")));
Boy boy = girl2.getBoy();
/*Optional<Boy> boyOptional = Optional.ofNullable(boy);
Boy boy1 = boyOptional.orElse(new Boy("王一博"));*/
return boy.getName();
}
public static void main(String[] args) {
Girl girl = null;
String girName2 = getGirName2(girl);
System.out.println(girName2);
Girl girl2 = new Girl(new Boy("王一博"));
String girName = getGirName2(girl2);
System.out.println(girName);
}
}
6. 总结:
- Stream 是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列,“集合讲的是数据,Stream 讲的是计算” 。
- Stream 的操作三个步骤:创建 Strem 流,中间操作,终止操作。
- Stream 创建的四种方式
- stream 和集合中的迭代器是一样的,不可多次不同结构的使用。 再次使用时需要新建一个 stream 对象,才能使用。简单的来说:就是 stream 对象一次只能对应一次操作,再进行一个新的操作时,必须新建一个 stream 对象才行。不然报
java.lang.IllegalStateException
异常。 - Stream 流一旦执行了终止操作后,就不能再使用了。
- Stream 自己不会存储元素。
- Stream 不会改变源对象,相反,他们会返回一个持有结果的新 Stream 。这一点和 String 不可变的特点类似。
- Stream 操作是延迟执行的。这意味着它们会等到需要结果的时候才执行。
- Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不 存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
7. 最后:
限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,江湖再见,后会有期 !!!