背景

到目前为止,臭名昭著的空指针异常是导致 Java 应用程序失败的最常见原因
以前,为了解决空指针异常,Google 公司著名的 Guava 项目引入了 Optional 类,Guava 通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional 类已经成为 Java 8 类库的一部分。

简介

  • Optional 实际上是个容器:它可以保存类型 T 的值,或者仅仅保存 null
  • Optional 提供很多有用的方法,这样我们就不用显式进行空值检测

17.3.1 API

如何创建 Optional 对象?或者说如何用 Optional 来装值对象或 null 值

  • static Optional empty() :用来创建一个空的 Optional
  • static Optional of(T value):用来创建一个非空的 Optional
  • static Optional ofNullable(T value):用来创建一个可能是空,也可能非空的 Optional

如何从 Optional 容器中取出所包装的对象呢?

T get()

  • 要求 Optional 容器必须非空
  • T get()of(T value)使用是安全的

T orElse(T other)

  • ofNullable(T value)配合使用
  • 如果 Optional 容器中非空,就返回包装值,如果为空,就用 other 指定的默认值(备胎)代替

T orElseGet(Supplier<? extends T> other)

如果 Optional 容器中非空,就返回包装值,如果为空,就用 Supplier 接口的 Lambda 表达式提供的值代替

T orElseThrow(Supplier<? extends X> exceptionSupplier)

如果 Optional 容器中非空,就返回所包装值,如果为空,就抛出指定的异常类型代替原来的 NoSuchElementException

其他方法

  • boolean isPresent():判断 Optional 容器中的值是否存在
  • void ifPresent(Consumer<? super T> consumer):判断 Optional 容器中的值是否存在,如果存在,就对它进行 Consumer 指定的操作,如果不存在就不做
  • Optional map(Function<? super T,? extends U> mapper):判断 Optional 容器中的值是否存在,如果存在,就对它进行 Function 接口指定的操作,如果不存在就不做
  • Optional<T> filter(Predicate<? super T> predicate):过滤 Optional 容器中的值,如果不存在返回空,如果存在则进行判断,不符合条件则返回 null,符合条件则返回自己本身 ```java package com.atguigu.test07;

import java.util.ArrayList; import java.util.Optional;

import org.junit.Test;

public class TestOptional { @Test public void test9(){ String str = “Hello”; Optional opt = Optional.ofNullable(str); //判断是否是纯字母单词,如果是,转为大写,否则保持不变 String result = opt.filter(s->s.matches(“[a-zA-Z]+”)). map(s -> s.toLowerCase()). orElse(str); System.out.println(result); }

  1. @Test
  2. public void test8(){
  3. String str = null;
  4. Optional<String> opt = Optional.ofNullable(str);
  5. String string = opt.orElseThrow(()->new RuntimeException("值不存在"));
  6. System.out.println(string);
  7. }
  8. @Test
  9. public void test7(){
  10. String str = null;
  11. Optional<String> opt = Optional.ofNullable(str);
  12. String string = opt.orElseGet(String::new);
  13. System.out.println(string);
  14. }
  15. @Test
  16. public void test6(){
  17. String str = "hello";
  18. Optional<String> opt = Optional.ofNullable(str);
  19. String string = opt.orElse("polo");
  20. System.out.println(string);
  21. }
  22. @Test
  23. public void test5(){
  24. String str = null;
  25. Optional<String> opt = Optional.ofNullable(str);

// System.out.println(opt.get());//java.util.NoSuchElementException: No value present }

@Test
public void test4(){
    String str = "hello";
    Optional<String> opt = Optional.of(str);

    String string = opt.get();
    System.out.println(string);
}


@Test
public void test3(){
    String str = null;
    Optional<String> opt = Optional.ofNullable(str);
    System.out.println(opt);
}

@Test
public void test2(){
    String str = "hello";
    Optional<String> opt = Optional.of(str);
    System.out.println(opt);
}

}


<a name="5b2f1e3b"></a>
### 17.3.2 练习
<a name="1e0d4029"></a>
#### 练习1

1. 声明一个 Girl 类型,包含姓名(String)属性
1. 声明一个 Boy 类型,包含姓名(String),女朋友(Girl)属性
1. 在测试类中,创建一个 Boy 对象,如果他有女朋友,显示他女朋友名称;如果他没有女朋友,他的女朋友默认为“嫦娥”
```java
class Girl{
    private String name;

    public Girl(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Girl [name=" + name + "]";
    }

}
class Boy{
    private String name;
    private Girl girlFriend;
    public Boy(String name, Girl girlFriend) {
        super();
        this.name = name;
        this.girlFriend = girlFriend;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Girl getGirlFriend() {
        return girlFriend;
    }
    public void setGirlFriend(Girl girlFriend) {
        this.girlFriend = girlFriend;
    }
    @Override
    public String toString() {
        return "Boy [name=" + name + ", girlFriend=" + girlFriend + "]";
    }

}

测试类

    public static void main(String[] args) {
//        Boy boy = new Boy("张三",null);
        Boy boy = new Boy("张三",new Girl("翠翠"));
        Optional<Girl> grilFriend = Optional.ofNullable(boy.getGirlFriend());
        Optional.of(grilFriend.orElse(new Girl("嫦娥"))).ifPresent(g->System.out.println(g));
    }

练习2

  1. 声明学生类,包含姓名和年龄
  2. 添加几个学生对象到一个 ArrayList 集合中
  3. 对集合中的学生进行操作,找出年龄大于30岁的,并取出第一个学生,如果没有这样的学生,用无参构造 new 一个学生对象,打印学生信息

学生类

class Student{
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}

测试类


    @Test
    public void test1(){
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("张三", 23));
        //...

        //取出流中第一个年龄大于30岁的学生的年龄,并打印它的年龄,如果没有,用无参构造创建一个学生对象
        Student stu = list.stream()
            .filter(s -> s.getAge()>30)
            .findFirst().orElse(new Student());
        System.out.println("学生的年龄:" + stu.getAge());
    }