函数编程:强大的 Stream API
函数编程:强大的 Stream API
每博一文案
只要有人的地方,世界就不会是冰冷的,我们可以平凡,但绝对不可以平庸。—————— 《平凡的世界》人活着,就得随时准备经受磨难。他已经看过一些书,知道不论是普通人还是了不起的人,
都要在自己的一生中经历许多磨难。磨难使人坚强。—————— 《平凡的世界》hellip... 人哪,活着是这么的苦,一旦你从幸福的彼岸被抛到苦难的此岸,你真
是处处走投无路,而现在你才知道,在天堂与地狱之间原来也只有一步之遥。——————《平凡的世界》
文章目录
- 函数编程:强大的 Stream API
- 每博一文案
- 1. Stream 的概述
- 1.1 为什么要使用Stream API
- 1.2 什么是 Stream
- 1.3 Stream 的操作三个步骤
- 1.4 Stream 与 Colliection 的区别
- 2. 创建 Stream 的四种方式
- 2.1 创建Stream 方式一:通过集合
- 2.2 创建 Stream 方式二:通过数组
- 2.3 创建 Stream 的方式三: 通过 Stream 的 of()
- 2.4 创建 Stream 方式四: 创建无限流
- 3. Stream 的中间操作
- 3.1 筛选与切片
- 3.2 映射
- 3.3 排序
- 4. Stream 的终止操作
- 4.1 匹配与查找
- 4.2 归约
- 4.3 收集
- 5.1 Optional类
- 5.2 创建 Optional 的三种方式
- 5.3 Optional 类中其他常用的方法
- 6. 总结:
- 7. 最后:
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,没有返回 fasleboolean 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. 最后:
限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,江湖再见,后会有期 !!!
相关文章:

函数编程:强大的 Stream API
函数编程:强大的 Stream API 每博一文案 只要有人的地方,世界就不会是冰冷的,我们可以平凡,但绝对不可以平庸。—————— 《平凡的世界》人活着,就得随时准备经受磨难。他已经看过一些书,知道不论是普通…...

企业架构图之业务架构图
在TOGAF的世界里面,所有的架构思想都可以通过下面三种类型的图形进行表示。 目录(Catalogs)矩阵(Matrix)图 (Diagram) 其架构图的本质就是用来进行沟通交流,通过架构图和业务团队进…...

监控易网络管理:网络流量分析
1、什么是网络流量分析2、网络流量分析的作用3、为什么要用网络流量分析功能,如何开启什么是网络流量分析简单的来说,网络流量分析就是捕捉网络中流动的数据包,并通过查看包内部数据以及进行相关的协议、流量、分析、统计等,协助发…...

RHCSA-文件内容显示(3.6)
查看命令 cat:显示文件内容 cat -n:显示文件内容的同时显示编号 tac:倒叙查看 head 文件名 (默认显示前10行):显示前10行 tail:显示末尾行数信息 more:查看文件信息,从头…...

Qt多线程文件查找器
⭐️我叫恒心,一名喜欢书写博客的研究生在读生。 原创不易~转载麻烦注明出处,并告知作者,谢谢!!! 这是一篇近期会不断更新的博客欧~~~ 有什么问题的小伙伴 欢迎留言提问欧。 Qt多线程文件查找器 前言 最近在实现一些代码功能的时候,需要找一些多线程样例来学习,于是就…...

源码阅读笔记 InputFormat、FileInputFormat、CombineTextInputFormat
1. InputFormat InputFormat是MapReduce框架提供的用来处理job输入的基类 它主要定义了三个功能: 1.验证job输入是否合法 2.对输入文件进行逻辑切片(InputSplit),然后将每个切片分发给单独的MapTask 3.提供切片读取器(Re…...

二值图像骨架线提取
二值图像骨架线提取HilditchThin算法Rosenfeld算法OpenCV_Contrib中的算法示例其他细化算法查表法HilditchThin的另一种算法参考二值图像骨架线提取算法:HilditchThin算法、Rosenfeld算法、OpenCV_Contrib中的算法 HilditchThin算法 1、使用的8邻域标记为ÿ…...

规划数据指标体系方法(上)——OSM 模型
之前我已经有写过文章讲了数据指标体系的搭建思路,但有同学还是不太清楚要从何入手,今天我就来跟大家讲一讲搭建数据指标体系之前第一步要先做的事情——规划数据指标体系。 规划数据指标体系,在业内有三种比较常见的方法,分别是&…...

做程序界中的死神,继续提升灵力上限
标题解读:标题中的死神,是源自《死神》动漫里面的角色,斩魂刀是死神的武器,始解是斩魂刀的初始解放形态,卐解是斩魂刀的觉醒解放形态,也是死神的大招。意旨做程序界中程序员的佼佼者,一步一步最…...

[数据结构]:11-冒泡排序(顺序表指针实现形式)(C语言实现)
目录 前言 已完成内容 冒泡排序实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-PSeqListFunction.cpp 04-SortCommon.cpp 05-SortFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容,除其中使用到C引用外,全为C语言代…...

Java实验报告经验总结
每一段是每一次实验报告写的经验总结,一共是一学期的内容 文章目录一二三四五六一 ~~~~~分析:这次做程序中也出了不少问题,究其根本还是没有理解清楚各语句功能和其应用。 ~~~~~比如说:当我们在定义浮点数时,数字的后面…...

ESP32使用TCP HTTP访问API接口JSON解析获取数据
ESP32使用TCP HTTP访问API接口JSON解析获取数据API接口代码解析获取时间代码烧录效果总结API接口 单片机常用的API接口基本都是返回的一串JSON格式的数据,这里以ESP32联网获取时间信息作为获取API数据的示例,以便后续移植使用。 很多功能性的API接…...

spring security 实现自定义认证和登录(4):使用token进行验证
前面我们实现了给客户端下发token,虽然客户端拿到了token,但我们还没处理客户端下一次携带token请求时如何验证,我们想要实现拿得到token之后,只需要验证token,不需要用户再携带用户名和密码了。 1. 禁用 UsernamePass…...

戴眼镜检测和识别2:Pytorch实现戴眼镜检测和识别(含戴眼镜数据集和训练代码)
Pytorch实现戴眼镜检测和识别(含戴眼镜数据集和训练代码) 目录 Pytorch实现戴眼镜检测和识别(含戴眼镜数据集和训练代码) 1.戴眼镜检测和识别方法 2.戴眼镜数据集 3.人脸检测模型 4.戴眼镜分类模型训练 (1)项目安装 (2)准…...

信息收集之Google Hacking
Google HackingGoogleHacking作为常用且方便的信息收集搜索引擎工具,它是利用谷歌搜索强大,可以搜出不想被看到的后台、泄露的信息、未授权访问,甚至还有一些网站配置密码和网站漏洞等。掌握了Google Hacking基本使用方法,或许下一…...

【面试题】如何避免使用过多的 if else?
大厂面试题分享 面试题库前后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库一、引言相信大家听说过回调地狱——回调函数层层嵌套,极大降低代码可读性。其实,if-else层层嵌套,如下图…...

oneblog_justauth_三方登录配置【Gitee】
文章目录oneblog添加第三方平台gitee中创建三方应用完善信息oneblog添加第三方平台 1.oneblog管理端,点击左侧菜单 网站管理——>社会化登录配置管理 ,添加一个社会化登录 2.编辑信息如下,选择gitee平台后复制redirectUri,然后去gitee获取clientId和…...

33- PyTorch实现分类和线性回归 (PyTorch系列) (深度学习)
知识要点 pytorch最常见的创建模型的方式, 子类 读取数据: data pd.read_csv(./dataset/credit-a.csv, headerNone) 数据转换为tensor: X torch.from_numpy(X.values).type(torch.FloatTensor) 创建简单模型: from torch import nn model nn.Sequential(nn.Linear(15, 1…...

C++基础——Ubuntu下编写C++环境配置总结(C++基本简介、Ubuntu环境配置、编写简单C++例程)
【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《QT开发实战》 《嵌入式通用开发实战》 《从0到1学习嵌入式Linux开发》 《Android开发实战》 《实用硬件方案设计》 长期持续带来更多案例与技术文章分享…...

项目管理中,导致进度失控的五种错误
项目管理中对工期的控制主要是进度控制,在项目进行中中,由于项目时间跨度长,人员繁杂,如果管理不规范,就容易导致项目进度滞后,如何管理好施工进度是管理者需要解决的问题之一。 1、项目计划缺乏执行力 安…...

C# 中的abstract和virtual
重新理解了下关键字abstract,做出以下总结: 1.标记为abstract的类不能实例化,但是依然可以有构造函数,也可以重载构造函数,在子类中调用 2.abstract类中可以有abstract标记的方法和属性,也可以没有,被标记…...

第六十周总结——React数据管理
React数据管理 代码仓库 React批量更新 React中的批量更新就是将多次更新合并处理,最终只渲染一次,来获得更好的性能。 React18版本之前的批量更新 // react 17 react-dom 17 react-scripts 4.0.3 import * as ReactDOM from "react-dom"…...

Springboot之@Async异步指定自定义线程池使用
开发中会碰到一些耗时较长或者不需要立即得到执行结果的逻辑,比如消息推送、商品同步等都可以使用异步方法,这时我们可以用到Async。但是直接使用 Async 会有风险,当我们没有指定线程池时,他会默认使用其Spring自带的 SimpleAsync…...

视频知识点(23)- TS格式详解指南
*《音视频开发》系列-总览*(点我) 一、格式简介 TS视频封装格式,是一种被广泛应用的多媒体文件格式。它的全称是MPEG2-TS,其中TS是“Transport Stream”的缩写。TS(Transport Stream)流是一种传输流,它由固定长度(188 字节)的 TS 包组成,TS 包是对PES包的一种封装方式…...

linux篇【16】:传输层协议<后序>
目录 六.滑动窗口 (1)发送缓冲区结构 (2)滑动窗口介绍 (3)滑动窗口不一定只会向右移动。滑动窗口可以变大也可以变小。 (4)那么如果出现了丢包, 如何进行重传? 这里分两种情况…...

【C语言】动态内存管理
一.为什么存在动态内存分配? 我们已经掌握的内存开辟方式有:int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟10个字节的连续空间 但是上述的开辟空间的方式有两个特点: 1. 空间开辟大小是固定的。 2. 数组在申明的…...

【Pytorch】AutoGrad个人理解
前提知识:[Pytorch] 前向传播和反向传播示例_友人小A的博客-CSDN博客 目录 简介 叶子节点 Tensor AutoGrad Functions 简介 torch.autograd是PyTorch的自动微分引擎(自动求导),为神经网络训练提供动力。torch.autograd需要对…...

华硕z790让独显和集显同时工作
系统用了一段时间,现在想让显卡主要做深度学习训练,集显用来连接显示器。却发现显示器接到集显接口无信号。 打售后客服也没有解决,现在把解决方案记录一下。 这是客服给的方案: 请开机后进BIOS---Advanced---System Agent (SA)…...

提高编程思维的python代码
1.通过函数取差。举例:返回有差别的列表元素 from math import floordef difference_by(a,b,fn):b set(map(fn, b))return [i for i in a if fn(i) not in b] print(difference_by([2.1, 1.2], [2.3, 3.4], floor))2.一行代码调用多个函数 def add(a, b):return …...

CSS背景background属性整理
1.background-color background-color属性:设置元素的背景颜色 2.background-position background-position属性:设置背景图像的起始位置,需要把 background-attachment 属性设置为 "fixed",才能保证该属性在 Firefo…...