# Optional 类

Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent () 方法会返回 true,调用 get () 方法会返回该对象。

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

Optional 类的引入很好的解决空指针异常。

# 类方法

方法描述
empty()返回空的 Optional 实例
equals(Object obj)判断其它对象是否等于 Optional
filter(Predicate<? super<T>> predicate)如果值存在,并且这个值匹配给定的 predicate,返回一个 <br />Optional 用以描述这个值,否则返回一个空的 Optional。
flatMap(Function<? super T, Optional<U>> mapper)如果值存在,返回基于 Optional 包含的映射方法的值 <br /> 否则返回一个空的 Optional
get()如果在这个 Optional 中包含这个值,返回值 <br /> 否则抛出异常:NoSuchElementException
hashCode()返回存在值的哈希码,如果值不存在 返回 0
ifPresent(Consumer<? super T> consumer)如果值存在则使用该值调用 consumer , 否则不做任何事情
ifPresent()如果值存在则方法会返回 true,否则返回 false
map(Function<? super T,? extends U> mapper)如果有值,则对其执行调用映射函数得到返回值 <br /> 如果返回值不为 null,则创建包含映射返回值的 Optional<br /> 作为 map 方法返回值,否则返回空 Optional
of(T value)返回一个指定非 null 值的 Optional
ofNullable(T value)如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional
orElse(T other)如果存在该值,返回值, 否则返回 other
orElseGet(Supplier<? extends T> other)如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果
orElseThrow(Supplier<? extends X> exceptionSupplier)如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
toString()返回一个 Optional 的非空字符串,用来调试

PS:这些方法都是从 java.lang.Object 类继承来的

# 简介

Optional 是一个对象容器,具有以下两个特点:

  • 提示用户要注意该对象有可能为null
    
  • 简化if else代码
    

# 代码演示:

需求:

学校想从一批学生中,选出年龄大于等于 18,参加过考试并且成绩大于 80 的人去参加比赛

import java.util.Arrays;
import java.util.List;
public class Student
{
    private String name;
    private int age;
    private Integer score;
    public Student()
    {
    }
    public Student(String name, int age, Integer score)
    {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    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;
    }
    public Integer getScore()
    {
        return score;
    }
    public void setScore(Integer score)
    {
        this.score = score;
    }
    @Override
    public String toString()
    {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
    public static void main(String[] args)
    {
        System.out.println(new Student().initData());
    }
    public List<Student> initData(){
        Student s1 = new Student("张三", 19, 80);
        Student s2 = new Student("李四", 19, 50);
        Student s3 = new Student("王五", 23, null);
        Student s4 = new Student("赵六", 16, 90);
        Student s5 = new Student("钱七", 18, 99);
        Student s6 = new Student("孙八", 20, 40);
        Student s7 = new Student("吴九", 21, 88);
        return Arrays.asList(s1, s2, s3, s4, s5, s6, s7);
    }
}

打印结果:

[Student{name='张三', age=19, score=80}, Student{name='李四', age=19, score=50}, Student{name='王五', age=23, score=null}, Student{name='赵六', age=16, score=90}, Student{name='钱七', age=18, score=99}, Student{name='孙八', age=20, score=40}, Student{name='吴九', age=21, score=88}]

# jdk8 之前的写法

public void beforeJava8() {
   List<Student> studentList = initData();
   for (Student student : studentList) {
      if (student != null) {
         if (student.getAge() >= 18) {
            Integer score = student.getScore();
            if (score != null && score > 80) {
               System.out.println("入选:" + student.getName());
            }
         }
      }
   }
}

打印结果:

[Student{name='张三', age=19, score=80}, Student{name='李四', age=19, score=50}, Student{name='王五', age=23, score=null}, Student{name='赵六', age=16, score=90}, Student{name='钱七', age=18, score=99}, Student{name='孙八', age=20, score=40}, Student{name='吴九', age=21, score=88}]
----jdk8之前的写法----
入选:钱七
入选:吴九

# jdk8 写法

public void useJava8() {
   List<Student> studentList = initData();
   for (Student student : studentList) {
      Optional<Student> studentOptional = Optional.of(student);
      Integer score = studentOptional.filter(s -> s.getAge() >= 18).map(Student::getScore).orElse(0);
      if (score > 80) {
         System.out.println("入选:" + student.getName());
      }
   }
}

打印结果:

[Student{name='张三', age=19, score=80}, Student{name='李四', age=19, score=50}, Student{name='王五', age=23, score=null}, Student{name='赵六', age=16, score=90}, Student{name='钱七', age=18, score=99}, Student{name='孙八', age=20, score=40}, Student{name='吴九', age=21, score=88}]
----jdk8之前的写法----
入选:钱七
入选:吴九
----jdk8的写法----
入选:钱七
入选:吴九

# 代码演示 2:

# Address

public class Address
{
    private House house;
    public House getHouse()
    {
        return house;
    }
    public void setHouse(House house)
    {
        this.house = house;
    }
}

# House

public class House
{
    private String name;
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
}

# User

public class User
{
    private String name;
    private int age;
    private Address address;
    public User()
    {
    }
    public User(String name, int age)
    {
        this.name = name;
        this.age = age;
    }
    public String getName()
    {
        return name;
    }
    public Address getAddress()
    {
        return address;
    }
    public void setAddress(Address address)
    {
        this.address = address;
    }
    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 "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

# Test

public class Test12
{
    public static void main(String[] args)
    {
        // Optional 基本的用法
        User user = new User("刘桑啊", 20);
        // 实际项目不会这么用,仅做简单介绍
        Optional<User> userOptional = Optional.ofNullable(user);
        User user1 = userOptional.get();
        System.out.println("user1 = " + user1);
        // Optional.of (null); 传入 null 抛异常
        // Optional.ofNullable (null); // 传啥都不会报错
        // 实际项目中这么用,如下:
        // 很好用,不用写!= null
        Optional.ofNullable(user).ifPresent(t -> System.out.println("user1不是null, 我才会执行"));
        Optional.ofNullable(user)
                .filter(t -> t.getName().contains("刘"))
                .ifPresent(t1 -> System.out.println("filter里是true的话我才能执行到"));
        // 传入 null 创建一个默认对象并返回
        // 如果传入的不是一个 null 而是一个实例化的对象那么就不会返回默认对象了,而是我们传入的对象
        User user2[] = getUser(/*user*/ null);
        for (User user3 : user2)
        {
            System.out.println(user3);
        }
        // 对象的复杂操作
        ObjectTest();
        // 关于异常
        Optional.ofNullable(null).orElseThrow(() -> new RuntimeException("我是异常,需要捕获"));
    }
    public static User[] getUser(User user)
    {
        // 为空的时候获取默认值
        // jdk1.9
        // Optional.ofNullable(user).or(() -> Optional.of(new User("admin", 17))).get();
        // jdk1.8
        User admin = Optional.ofNullable(user).orElse(new User("admin", 90));
        //jdk1.8 orElseGet 接收一个函数式接口
        User admin1 = Optional.ofNullable(user).orElseGet(() -> new User("admin", 24));
        return new User[]{admin, admin1};
    }
    private static void ObjectTest()
    {
        User user = new User();
        Address address = new Address();
        House house = new House();
        house.setName("刘桑的房子");
        address.setHouse(house);
        user.setAddress(address);
        // 将 user 存入 optional 得到 optional
        Optional<User> userOptional = Optional.ofNullable(user);
        String name = userOptional
                // 如果不为 null,创建包含映射返回值的 optional
                .map(u -> u.getAddress())
                .map(address1 -> address1.getHouse())
                .map(house1 -> house1.getName())
                .orElse("default");
        System.out.println(name);
        // 效果和上面一样
        String s = userOptional
                .flatMap(u -> Optional.ofNullable(u.getAddress()))
                .flatMap(address1 -> Optional.ofNullable(address1.getHouse()))
                .flatMap(house1 -> Optional.ofNullable(house1.getName())).orElse("default");
        System.out.println(s);
    }
}

打印结果:

user1 = User{name='刘桑啊', age=20}
user1不是null, 我才会执行
filter里是true的话我才能执行到
User{name='admin', age=90}
User{name='admin', age=24}
刘桑的房子
刘桑的房子
Exception in thread "main" java.lang.RuntimeException: 我是异常,需要捕获
	at com.dkx.Test12.lambda$main$3(Test12.java:34)
	at java.util.Optional.orElseThrow(Optional.java:290)
	at com.dkx.Test12.main(Test12.java:34)