• Java 8 新特性 (#Lambda表达式 #函数式(Functional)接口 #方法引用与构造器引用 #Stream API #Optional类)


    • 概述

    Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Java 8 是oracle公司于2014年3月发布,可以看成是自Java 5 以 来最具革命性的版本。Java 8为Java语言、编译器、类库、开发 工具与JVM带来了大量新特性。

    • 速度更快
    • 代码更少(增加了新的语法:Lambda 表达式)
    • 强大的 Stream API
    • 便于并行
    • 最大化减少空指针异常:Optional
    • Nashorn引擎,允许在JVM上运行JS应用

    •  Lambda

    Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以 传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了 提升。

    语法格式

    Lambda表达式:在Java 8 语言中引入的一种新的语法元素和操作符。这个操作符为 “->” ,该操作符被称为Lambda操作符或箭头操作符。

    箭头操作符将Lambda分为两个部分:

    • 左侧:指定了 Lambda 表达式需要的参数列表
    • 右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能。 

    六大格式

    格式一:无参,无返回值

    Runnable r2 = () -> {System.out.println("我也是中国人!");};

    格式二:Lambda 需要一个参数,但是没有返回值。 

     Consumer con2 = (String s) -> {System.out.println(s);};

     格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”

     Consumer con2 = (s) -> {System.out.println(s);};

    法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略 

     Consumer con2 = s -> {System.out.println(s);};

    格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值

    1. Comparator com2 = (o1,o2) -> {
    2. System.out.println("xxxxxxxxx");
    3. return Integer.compare(o1,o2);
    4. };

     格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略

    Comparator com2 = (o1,o2) -> Integer.compare(o1,o2);
    • 函数式(Functional)接口

    理解函数式接口

    • Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)
    • 在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的 编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在 Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的 对象类型——函数式接口。 
    • 简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口 的实例,那么该对象就可以用Lambda表达式来表示。
    • 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

    函数式接口的特点

    • 只包含一个抽象方法的接口,称为函数式接口。
    • 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式 抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽 象方法上进行声明)。
    • 我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检 查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个 接口是一个函数式接口。
    • 在java.util.function包下定义了Java 8 的丰富的函数式接口 

    自定义函数式接口

    1. @FunctionalInterface
    2. public interface A {
    3. String show(String s);
    4. }

     函数式接口中使用泛型

    1. @FunctionalInterface
    2. public interface A<T> {
    3. public T show(T t);
    4. }

    用Lambda表达式实例化自定义函数接口

    1. @Test
    2. public void test11(){
    3. //***********常规写法***************"
    4. A a = new A() {
    5. @Override
    6. public String show(String s) {
    7. return s;
    8. }
    9. }
    10. String zz = (String) a.show("zz");
    11. System.out.println(zz);
    12. //***********Lambda表达式写法***************"
    13. A a1 = s -> s;
    14. String yy = (String) a1.show("yy");
    15. System.out.println(yy);
    16. }

    作为参数传递 Lambda 表达式

    1. @Test
    2. public void test22(){
    3. List list = Arrays.asList("北京","南京","天津","东京","西京");
    4. //"***********常规写法***************
    5. filterString(list, new Predicate() {
    6. @Override
    7. public boolean test(String s) {
    8. return s.contains("京");
    9. }
    10. });
    11. //****************Lambda表达式写法***************
    12. List list1 = filterString(list, s -> s.contains("京"));
    13. System.out.println(list1);
    14. }
    15. //根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
    16. public List filterString(List list, Predicate pre){
    17. List filterList = new ArrayList<>();
    18. for (String s : list) {
    19. if (pre.test(s))
    20. filterList.add(s);
    21. }
    22. return filterList;
    23. }

    Java 内置四大核心函数式接口

    • 方法引用、构造器引用、数组引用

    方法引用

    概述

    • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
    • 方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。 
    • 使用格式:  类(或对象) :: 方法名
    • 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对于下文的情况1和情况2)
    • 具体分为如下的三种情况:
    1.  对象 :: 非静态方法
    2.  类 :: 静态方法
    3.  类 :: 非静态方法

    情况一:对象 :: 实例方法

    1. @Test
    2. public void test1(){
    3. Person p = new Person("张三",23);
    4. //***********常规写法***************"
    5. Supplier sup = new Supplier() {
    6. @Override
    7. public String get() {
    8. return p.getName();
    9. }
    10. };
    11. String s = sup.get();
    12. System.out.println(s);
    13. //***********Lambda表达式写法***************"
    14. Supplier<String> sup1 = () -> p.getName();
    15. System.out.println(sup1.get());
    16. //***********方法引用写法***************"
    17. Supplier sup2 = p :: getName;
    18. System.out.println(sup2.get());
    19. }

     情况二:类 :: 静态方法

    1. @Test
    2. public void test2(){
    3. //***********常规写法***************"
    4. Comparator com1 = new Comparator() {
    5. @Override
    6. public int compare(Integer o1, Integer o2) {
    7. return Integer.compare(o1,o2);//Integer类的静态方法compare()
    8. }
    9. };
    10. System.out.println(com1.compare(11, 22));//-1
    11. //***********Lambda表达式写法***************"
    12. Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1,o2);
    13. System.out.println(com2.compare(22,11));//1
    14. //***********方法引用写法***************"
    15. Comparator com3 = Integer::compare;
    16. System.out.println(com3.compare(22, 33));//-1
    17. }

    情况三:类 :: 非静态方法

    1. @Test
    2. public void test3(){
    3. //***********常规写法***************"
    4. Comparator com1 = new Comparator() {
    5. @Override
    6. public int compare(String o1, String o2) {
    7. return o1.compareTo(o2);
    8. }
    9. };
    10. System.out.println(com1.compare("AA", "AB"));//-1
    11. //***********Lambda表达式写法***************"
    12. Comparator<String> com2 = (o1, o2) -> o1.compareTo(o2);
    13. System.out.println(com2.compare("AB", "AA"));
    14. //***********方法引用写法***************"
    15. Comparator com3 = String :: compareTo;
    16. System.out.println(com3.compare("AB", "AC"));//-1
    17. }

    构造器引用

     概述

    • 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
    • 抽象方法的返回值类型即为构造器所属的类的类型 
    • 格式:ClassName::new

    代码演示

    空参构造器引用

    1. @Test
    2. public void test1(){
    3. //***********常规写法***************"
    4. Supplier sup1 = new Supplier() {
    5. @Override
    6. public Person get() {
    7. return new Person();
    8. }
    9. };
    10. Person person = sup1.get();
    11. System.out.println(person);
    12. //***********Lambda表达式写法***************"
    13. Supplier<Person> sup2 = () -> new Person();
    14. System.out.println(sup2.get());
    15. //***********构造器引用写法***************"
    16. Supplier sup3 = Person :: new;
    17. System.out.println(sup3.get());
    18. }

    带参构造器方法引用

    1. @Test
    2. public void test2(){
    3. //***********常规写法***************"
    4. BiFunction bf1 = new BiFunction() {
    5. @Override
    6. public Person apply(String s, Integer integer) {
    7. return new Person(s,integer);
    8. }
    9. };
    10. Person p1 = bf1.apply("Jack", 23);
    11. System.out.println(p1);
    12. //***********Lambda表达式写法***************"
    13. BiFunction<String,Integer,Person> bf2 = (s,integer) -> new Person(s,integer);
    14. System.out.println(bf2.apply("Tom", 24));
    15. //***********构造器引用写法***************"
    16. BiFunction bf3 = Person :: new;
    17. System.out.println(bf3.apply("Jerry", 25));
    18. }

    数组引用

    概述

    可以把数组看做是一个特殊的类,则写法与构造器引用一致。

    代码演示

    1. @Test
    2. public void test3(){
    3. //***********常规写法***************"
    4. Function fun1 = new Function() {
    5. @Override
    6. public String[] apply(Integer integer) {
    7. return new String[integer];
    8. }
    9. };
    10. String[] arr1 = fun1.apply(5);
    11. System.out.println(Arrays.toString(arr1));
    12. //***********Lambda表达式写法***************"
    13. Function<Integer,String[]> fun2 = length -> new String[length];
    14. System.out.println(Arrays.toString(fun2.apply(6)));
    15. //***********数组引用写法***************"
    16. Function fun3 = String[] ::new;
    17. System.out.println(Arrays.toString(fun3.apply(7)));
    18. }
    • 强大的Stream API

    概述

    说明

    • Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用 Stream API 对集合数据进行操作,就类似于使用 SQL执行的数据库查询。 也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种 高效且易于使用的处理数据的方式。 
    • 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数 据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要 Java层面去处理。

    Stream 和 Collection 集合的区别 

    Stream关注的是对数据的运算,与CPU打交道。集合关注的是数据的存储,与内存打交道 (“集合讲的是数据,Stream讲的是计算!)

    Stream的特点

    • Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 
    • Stream 自己不会存储元素。
    • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
    • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行 

    Stream执行流程

    1. Stream的实例化
    2.  一系列的中间操作(过滤、映射、...)
    3.  终止操作 

    注意 :

    • 一个中间操作链,对数据源的数据进行处理
    • 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

    Stream的实例化(创建Stream)

    方式一:通过集合 

    1. @Test
    2. public void test1(){
    3. List<Person> peoples = new ArrayList<>();
    4. peoples.add(new Person("张三",23));
    5. peoples.add(new Person("李四",24));
    6. peoples.add(new Person("王五",25));
    7. peoples.add(new Person("赵六",26));
    8. //default Stream<E> stream() : 返回一个顺序流
    9. Stream<Person> stream = peoples.stream();
    10. //default Stream<E> parallelStream() : 返回一个并行流
    11. Stream<Person> stream1 = peoples.parallelStream();
    12. }

     方式二:通过数组

    1. public void test2(){
    2. Person p1 = new Person("张三",23);
    3. Person p2 = new Person("李四",24);
    4. //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
    5. Person[] peoples = new Person[]{p1,p2};
    6. Stream<Person> stream = Arrays.stream(peoples);
    7. }

     方式三:通过Stream的of()

    1. @Test
    2. public void test3(){
    3. Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六");
    4. }

     方式四:创建无限流

    1. @Test
    2. public void test4(){
    3. //迭代
    4. //public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    5. Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println);
    6. //生成
    7. //public static<T> Stream<T> generate(Supplier<T> s)
    8. Stream.generate(Math::random).limit(10).forEach(System.out::println);
    9. }

    Stream的中间操作

    说明

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

    筛选与切片

    •  filter(Predicate p) 接收 Lambda , 从流中排除某些元素
      1. List workersList = WorkerData.getWorkers();
      2. Stream stream = workersList.stream();
      3. //filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
      4. stream.filter(w -> w.getSalary() > 5000).forEach(System.out::println);//查询员工表中薪资大于5000的员工信息
    • distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
      1. List workersList = WorkerData.getWorkers();
      2. //distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
      3. workersList.add(new Worker(1004, "雷军", 26, 7657.37));//原集合存在该条数据去重
      4. workersList.add(new Worker(1004, "雷军", 26, 8888));//和原数据salary不同,不会去除该条数据
      5. workersList.stream().distinct().forEach(System.out::println);
    • limit(long maxSize) 截断流,使其元素不超过给定数量
      1. List workersList = WorkerData.getWorkers();
      2. // limit(n)——截断流,使其元素不超过给定数量。
      3. workersList.stream().limit(3).forEach(System.out::println);//获取集合中前三条数据
    • skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一 个空流。与 limit(n) 互补
      1. List workersList = WorkerData.getWorkers();
      2. //skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
      3. workersList.stream().skip(3).forEach(System.out::println);//获取集合中除了前三条的其余数据

      映射

    • map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
      1. @Test
      2. public void test(){
      3. //通过集合实例化Stream
      4. Stream workerStream = WorkerData.getWorkers().stream();
      5. //通过map()方法反射出集合中所有员工名字
      6. Stream streamName = workerStream.map(Worker::getName);
      7. //筛选出员工姓名长度大于3的员工的姓名。
      8. streamName.filter(name -> name.length() > 3).forEach(System.out::println);
      9. }
    • mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
    • mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
    • mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
    • flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 
      1. @Test
      2. public void test9(){
      3. List list = Arrays.asList("aa", "bb", "cc", "dd");
      4. //Stream里还有Stream时,通过使用map()方法需要使用二次forEach()方法进行终止操作
      5. //可以通过集合添加元素的add()方法和addAll()方法进行理解
      6. Stream> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
      7. streamStream.forEach(s -> s.forEach(System.out::println));
      8. System.out.println("****************");
      9. //这里我们可以使用flatMap(Function f)方法进行处理者这种情况(相当于集合添加元素的addAll()方法)
      10. Stream streamStream1 = list.stream().flatMap(StreamAPITest1::fromStringToStream);
      11. streamStream1.forEach(System.out::println);
      12. }
      13. //将字符串中的多个字符构成的集合转换为对应的Stream的实例
      14. public static Stream fromStringToStream(String s){
      15. ArrayList list = new ArrayList<>();
      16. for (Character c : s.toCharArray()) {
      17. list.add(c);
      18. }
      19. return list.stream();
      20. }

    排序

    • sorted() 产生一个新流,其中按自然顺序排序
      1. @Test
      2. public void test5(){
      3. List list = Arrays.asList(11,22,44,77,33,55);
      4. list.stream().sorted().forEach(System.out::println);
      5. }

    注意:自定义类要实现Comparable接口,才能使用sorted()方法

    • sorted(Comparator com) 产生一个新流,其中按比较器顺序排序 (定制排序)
      1. @Test
      2. public void test6(){
      3. List workerList = WorkerData.getWorkers();
      4. workerList.stream().sorted((o1,o2) ->{
      5. int compareAge = Integer.compare(o1.getAge(),o2.getAge());
      6. if (compareAge != 0)
      7. return compareAge;
      8. else {
      9. int compareSalary = -Double.compare(o1.getSalary(), o2.getSalary());
      10. return compareSalary;
      11. }
      12. }).forEach(System.out::println);
      13. }

      Stream的终止操作(终端操作)

     匹配与查找

    以下代码演示需要用到的Worker类的对象集合:

    List workerList = WorkerData.getWorkers();
    • allMatch(Predicate p) 检查是否匹配所有元素
      1. //需求:是否所有的员工的年龄都大于18
      2. boolean b = workerList.stream().allMatch(w -> w.getAge() > 20);
      3. System.out.println(b);
    • anyMatch(Predicate p) 检查是否至少匹配一个元素
      1. //需求:是否存在员工的工资大于 10000
      2. boolean b1 = workerList.stream().anyMatch(w -> w.getSalary() > 10000);
      3. System.out.println(b1);
    • noneMatch(Predicate p) 检查是否没有匹配所有元素
      1. //需求:是否存在员工姓“雷”
      2. boolean b2 = workerList.stream().noneMatch(w -> w.getName() == "张");
      3. System.out.println(b2);
    • findFirst() 返回第一个元素
      1. Optional first = workerList.stream().findFirst();
      2. System.out.println(first);
    • findAny() 返回当前流中的任意元素 
      1. Optional any = workerList.parallelStream().findAny();
      2. System.out.println(any);
    • count() 返回流中元素总数
      1. //需求:计算员工工资大于5000的员工个数
      2. long count = workerList.stream().filter(w -> w.getSalary() > 5000).count();
      3. System.out.println(count);
    • max(Comparator c) 返回流中最大值
      1. //需求:查找最高的员工工资
      2. Optional maxSalary = workerList.stream().map(w -> w.getSalary()).max(Double::compare);
      3. System.out.println(maxSalary);
    • min(Comparator c) 返回流中最小值
      1. //需求:查找最低的员工工资
      2. //写法一:
      3. Optional min = workerList.stream().map(w -> w.getSalary()).min((o1,o2) -> Double.compare(o1,o2));
      4. System.out.println(min);//Optional[2500.32]
      5. //写法一:
      6. Optional minSalary = workerList.stream().min((w1, w2) -> Double.compare(w1.getSalary(), w2.getSalary()));
      7. System.out.println(minSalary);//Optional[Worker{id=1008, name='扎克伯格', age=35, salary=2500.32}]
    • forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代, 称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了) 
      1. //使用集合的遍历操作
      2. workerList.forEach(System.out::println);
      3. System.out.println();
      4. //内部迭代
      5. workerList.stream().forEach(System.out::println);

    规约

    map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。

    • reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一 个值。返回 T
      1. //练习1:计算1-10的自然数的和
      2. List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
      3. Integer sum = list.stream().reduce(0, (o1, o2) -> Integer.sum(o1, o2));
      4. //Integer sum = list.stream().reduce(0, Integer::sum);
      5. System.out.println(sum);//55
    • reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一 个值。返回 Optional  
      1. List workerList = WorkerData.getWorkers();
      2. Optional sumSalary = workerList.stream().map(w -> w.getSalary()).reduce((s1, s2) -> s1 + s2);
      3. System.out.println(sumSalary);//Optional[48424.08]

    收集

    •  collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
      1. @Test
      2. public void test3(){
      3. List workerList = WorkerData.getWorkers();
      4. //把流中元素收集到List集合中
      5. List collectList = workerList.stream().filter(w -> w.getSalary() > 5000).collect(Collectors.toList());
      6. collectList.forEach(System.out::println);
      7. System.out.println();
      8. //把流中元素收集到set集合中
      9. Set collectList1 = workerList.stream().filter(w -> w.getSalary() > 5000).collect(Collectors.toSet());
      10. collectList1.forEach(System.out::println);
      11. }

      Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、 Map)。 另外,Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:

    • Optional类

    概述

    • 为了解决空指针异常,Google公司著名的Guava项目引入了Optional类, Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代 码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。 
    • Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不 存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
    • Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

    创建Optional类对象的方法

    下方代码演示用到的Student类和Teacher类  

    1. public class Student {
    2. private String name;
    3. public Student() {
    4. }
    5. public Student(String name) {
    6. this.name = name;
    7. }
    8. public String getName() {
    9. return name;
    10. }
    11. public void setName(String name) {
    12. this.name = name;
    13. }
    14. @Override
    15. public String toString() {
    16. return "Student{" +
    17. "name='" + name + '\'' +
    18. '}';
    19. }
    20. }
    1. public class Teacher {
    2. private Student student;
    3. public Teacher() {
    4. }
    5. public Teacher(Student student) {
    6. this.student = student;
    7. }
    8. public Student getStudent() {
    9. return student;
    10. }
    11. public void setStudent(Student student) {
    12. this.student = student;
    13. }
    14. @Override
    15. public String toString() {
    16. return "Teacher{" +
    17. "student=" + student +
    18. '}';
    19. }
    20. }
    • Optional.of(T t) : 创建一个 Optional 实例,t必须非空
    1. @Test
    2. public void test1(){
    3. Student student = new Student();
    4. //student = null;//java.lang.NullPointerException
    5. Optional optionalStudent = Optional.of(student);
    6. }
    • Optional.ofNullable(T t):t可以为null 
    1. @Test
    2. public void test2(){
    3. Student student = new Student();
    4. student = null;
    5. //ofNullable(T t):t可以为null
    6. Optional optionalStudent = Optional.ofNullable(student);
    7. }
    • Optional.empty() : 创建一个空的 Optional 实例
    Optional empty = Optional.empty(); 
    

     判断Optional容器中是否包含对象

    • boolean isPresent() : 判断是否包含对象
      1. @Test
      2. public void test4() {
      3. Student student = new Student();
      4. //student = null;
      5. Optional optionalStudent = Optional.ofNullable(student);
      6. boolean present = optionalStudent.isPresent();
      7. System.out.println(present);//true(如果对象为null 返回为false)
      8. }
    • void ifPresent(Consumer consumer) :如果有值,就执行Consumer 接口的实现代码,并且该值会作为参数传给它。
      1. @Test
      2. public void test5(){
      3. Student stu = new Student();
      4. stu.setName("张三");
      5. //stu = null;//如果对象为null时,ifPresent()方法返回为空
      6. Optional optionalStudent = Optional.ofNullable(stu);
      7. //方式1:
      8. optionalStudent.ifPresent(student -> System.out.println(student.getName()));
      9. //方式二:
      10. optionalStudent.ifPresent(new Consumer() {
      11. @Override
      12. public void accept(Student student) {
      13. System.out.println(student.getName());
      14. }
      15. });
      16. }

      获取Optional容器的对象 

    • T get(): 如果调用对象包含值,返回该值,否则抛异常
      1. @Test
      2. public void test6(){
      3. Student student = new Student();
      4. Optional optionalStudent = Optional.of(student);
      5. Student stu = optionalStudent.get();
      6. System.out.println(stu);
      7. }
    • T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。
      1. public String getStudentName(Teacher teacher){
      2. //return teacher.getStudent().getName();//这样写会出现空指针异常
      3. //Java1.8之前没引进Optional类的写法
      4. /*if (teacher != null) {
      5. Student student = teacher.getStudent();
      6. if (student != null){
      7. return student.getName();
      8. }
      9. }
      10. return null;*/
      11. //Java1.8引进Optional类的写法
      12. Optional teacher1 = Optional.ofNullable(teacher);
      13. //此时的teacher2一定非空(如果teacher1为空,则返回Jerry,如果不为空,则返回实际的对象)
      14. Teacher teacher2 = teacher1.orElse(new Teacher(new Student("Jerry")));
      15. Student student = teacher2.getStudent();
      16. Optional student1 = Optional.ofNullable(student);
      17. //此时的student2一定非空(如果student1为空,则返回Tom,如果不为空,则返回实际的对象)
      18. Student student2 = student1.orElse(new Student("Tom"));
      19. return student2.getName();
      20. }
    • T orElseGet(Supplier other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
      1. @Test
      2. public void test8(){
      3. Teacher teacher = new Teacher(new Student("Jane"));
      4. Optional teacher1 = Optional.ofNullable(teacher);
      5. Teacher teacher2 = teacher1.orElseGet(() -> new Teacher(new Student("Jerry")));
      6. Student student = teacher2.getStudent();
      7. Optional student1 = Optional.ofNullable(student);
      8. Student student2 = student1.orElseGet(new Supplier() {
      9. @Override
      10. public Student get() {
      11. return new Student("Tom");
      12. }
      13. });
      14. System.out.println(teacher2);//Teacher{student=Student{name='Jane'}}
      15. System.out.println(student2);//Student{name='Jane'}
    • T orElseThrow(Supplier exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
      1. @Test
      2. public void test9() throws Throwable {
      3. Teacher teacher = new Teacher();
      4. teacher = null;
      5. Optional teacher1 = Optional.ofNullable(teacher);
      6. Teacher teacher2 = teacher1.orElseThrow(new Supplier() {
      7. @Override
      8. public Throwable get() {
      9. return new MyException("异常", 001);
      10. }
      11. });
      12. System.out.println(teacher2);
      13. }
  • 相关阅读:
    【MybatisPlus】MP解决四种表与实体的映射问题,以及id自增策略
    自媒体平台上剪视频的素材都是从哪来的?
    Git学习笔记(五)IDEA使用Git
    缓存与数据一致性问题
    springcloud-网关(gateway)
    如何完美卸载Visual Studio 2013
    centos7 + citus12 + postgresql 14 安装
    STM32day2
    【无标题】
    百度飞桨(PaddlePaddle) - PP-OCRv3 文字检测识别系统 Paddle Inference 模型推理
  • 原文地址:https://blog.csdn.net/m0_58052874/article/details/126832810