optional使用

简介

Optional类是Java8为了解决null值判断问题而引入的,使用Optional类可以避免显式的null值判断(null的防御性检查),避免null导致的NPE(NullPointerException)


常用api

构建optional相关

  1. 创建一个包装对象值为空的Optional对象,很少用

     Optional optional = Optional.empty();

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /**
    * Common instance for {@code empty()}.
    */
    private static final Optional<?> EMPTY = new Optional<>();

    public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
    }
  2. 创建包装对象值非空的Optional对象,传入的value必须为非空,有校验空则报空指针异常

    Optional optional = Optional.of(“optional”);

    1
    2
    3
    4
    5
    6
    7
    private Optional(T value) {
    this.value = Objects.requireNonNull(value);
    }

    public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
    }
  3. 创建包装对象值允许为空的Optional对象,最常用

    Optional optional = Optional.ofNullable(null);

    1
    2
    3
    public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
    }

取值

  1. get方法

    get方法主要用于返回包装对象的实际值,但是如果包装对象值为null,会抛出NoSuchElementException异常

    1
    2
    3
    4
    5
    6
    public T get() {
    if (value == null) {
    throw new NoSuchElementException("No value present");
    }
    return value;
    }
  2. orElse方法

    orElse方法功能比较简单,即如果包装对象值非空,返回包装对象值,否则返回入参other的值

    1
    2
    3
    public T orElse(T other) {
    return value != null ? value : other;
    }
  3. orElseGet方法

    orElseGet方法与orElse()方法类似,区别在于orElseGet()方法的入参为一个Supplier对象,用Supplier对象的get()方法的返回值作为默认值

    1
    2
    3
    public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
    }
  4. orElseThrow方法

    orElseThrow方法其实与orElseGet()方法非常相似,入参都是Supplier对象,但orElseThrow()的Supplier对象必须返回一个Throwable异常,并在orElseThrow()中将异常抛出,适用于包装对象值为空时需要抛出特定异常的场景。

    1
    2
    3
    4
    5
    6
    7
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
    return value;
    } else {
    throw exceptionSupplier.get();
    }
    }

处理

  1. ifPresent方法

    ifPresent方法接受一个Consumer对象(消费函数),如果包装对象的值非空,运行Consumer对象的accept()方法。示例如下:

    1
    2
    3
    4
    public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
    consumer.accept(value);
    }
  2. isPresent方法

    isPresent方法用于判断包装对象的值是否非空

    1
    2
    3
    public boolean isPresent() {
    return value != null;
    }
  3. map方法

    map方法的参数为Function(函数式接口)对象,map()方法将Optional中的包装对象用Function函数进行运算,并包装成新的Optional对象(包装对象的类型可能改变)

    1
    2
    3
    4
    5
    6
    7
    8
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
    return empty();
    else {
    return Optional.ofNullable(mapper.apply(value));
    }
    }
  4. filter方法

    filter方法接受参数为Predicate对象,用于对Optional对象进行过滤,如果符合Predicate的条件,返回Optional对象本身,否则返回一个空的Optional对象

    1
    2
    3
    4
    5
    6
    7
    public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
    return this;
    else
    return predicate.test(value) ? this : empty();
    }

综合应用实战篇

基础类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Data
class Person{

private int age;

private String name;

private Address address;
}

@Data
class Address{
/**
* 城市名称
*/
private String cityName;

}

public class OptionalTest {


//模拟调用外部方法,获取person对象,可能为空值
private static Person buildPerson(){
if (new Random().nextBoolean()) {
Person person = new Person();
person.setAge(18);
person.setName("chenghao");
Address address = new Address();
address.setCityName("shanghai");
person.setAddress(address);
return person;
}
return null;
}
}
1 取个人所在城市不为空的进行输出

传统方法

1
2
3
4
5
6
7
8
9
10
private static String getCityName(){
Person person = buildPerson();
if(Objects.nonNull(person)){
Address address = person.getAddress();
if (Objects.nonNull(address)){
return address.getCityName();
}
}
return null;
}

使用optional改造

1
2
3
4
5
6
7
private static String getCityName2(){
Person person = buildPerson();
return Optional.ofNullable(person)
.map(Person::getAddress)
.map(Address::getCityName)
.orElse(null);
}
2 获取固定名称的人,person由外部调用产生,可能为空

传统方法

1
2
3
4
5
6
7
8
private static Person getPerson(Person person){
if(Objects.nonNull(person) && "chenghao".equals(person.getName())){
return person;
}
Person newPerson = new Person();
newPerson.setName("chenghao");
return newPerson;
}

使用optional改造

1
2
3
4
5
6
7
8
private static Person getPerson2(Person person){
return Optional.ofNullable(person).filter(p -> "chenghao".equals(p.getName()))
.orElseGet(() -> {
Person person1 = new Person();
person1.setName("chenghao");
return person1;
});
}