01f2e8ee4f910242e73203a87d2f9f6b.png

一、Optional介绍

java.util.Optional是一个Java JDK8引入的类,借鉴了Google Guava工具包的Optional类,其目的是为了避免空指针问题(java.lang.NullPointerException)。

Optional是一个容器类,它可以存放空值或非空值对象,通过函数式方法进行判断、过滤和映射等操作,对空值进行处理并返回Optional对象。

二、实例方法

1、empty

empty,直接创建一个EMPTY实例,空值的Optional对象。

/**
  * Common instance for {@code empty()}.
  */
private static final Optional<?> EMPTY = new Optional<>();
​
/**
  * Returns an empty {@code Optional} instance.  No value is present for this 
  * Optional.
  */
public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

仔细查看源码,EMPTY参数直接指向一个Optional对象,如果去掉了final修饰符,看起来不就是懒汉式单例吗,于是有了以下的测试用例。

该功能就表明,我们可以使用==和Optional.empty()比较,就可以判断出对象是不是为空,从而避开空指针问题。当然也可以使用isPresent()方法,同样可以实现判断空值的效果。

public static void main(String[] args) {
    PersonEntity person = null;
    Optional optional1 = Optional.ofNullable(person);
    Optional optional2 = Optional.empty();
    // 返回结果:true
    System.out.println(optional1 == optional2);
}

2、of

of,创建一个不为空值的Optional对象,如果传入空值会报NullPointerException。

/**
 * Returns an {@code Optional} with the specified present non-null value.
 */
public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}

3、ofNullable

ofNullable,创建一个可空值也可非空值的Optional对象,当不确定value值是否为空时可以使用。

通过源码可以分析,value为空值使用empty()方法,为非空值使用of()方法。

/**
 * Returns an {@code Optional} describing the specified value, if non-null,
 * otherwise returns an empty {@code Optional}.
 */
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

三、获取value

1、get

get,获取Optional对象的value值,如果value为EMPTY,那会抛出NoSuchElementException异常。

所以使用该方法前,最好使用isPresent()方法判断是否为空。

/**
 * If a value is present in this {@code Optional}, returns the value,
 * otherwise throws {@code NoSuchElementException}.
 */
public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}
​
// 测试用例
public static void main(String[] args) {
    PersonEntity person = new PersonEntity("张三", 18);
    Optional optional = Optional.ofNullable(person);
    System.out.println(optional.get());
    /*
     * 返回结果:PersonEntity(name=张三, age=18)
     */
    
    PersonEntity person2 = null;
    Optional optional2 = Optional.ofNullable(person2);
    System.out.println(optional2.get());
    /*
     * 抛异常:java.util.NoSuchElementException: No value present
     */
}

2、orElse

orElse,获取Optional对象的value值,如果value为EMPTY,则返回other对象,相当于为空值判断而设置默认对象。

/**
 * Return the value if present, otherwise return {@code other}.
 */
public T orElse(T other) {
    return value != null ? value : other;
}
​
// 测试用例
public static void main(String[] args) {
    PersonEntity defaultPerson = new PersonEntity("李四", 15);
    PersonEntity person = null;
    Optional optional = Optional.ofNullable(person);
    System.out.println(optional.orElseGet(defaultPerson));
    /*
     * 返回结果:PersonEntity(name=李四, age=15)
     */
}

3、orElseGet

orElseGet,获取Optional对象的value值,如果value为EMPTY,则使用Supplier供给型接口来获取默认值。

/**
 * Return the value if present, otherwise invoke {@code other} and return
 * the result of that invocation.
 */
public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}
​
// 测试用例
public static void main(String[] args) {
    PersonEntity person = null;
    Optional<PersonEntity> optional = Optional.ofNullable(person);
    System.out.println(optional.orElseGet(() -> new PersonEntity("王五", 20)));
    /*
     * 返回结果:PersonEntity(name=王五, age=20)
     */
}

4、orElseThrow

orElseThrow,获取Optional对象的value值,如果value为EMPTY,则使用Supplier供给型接口来创建抛出异常。

/**
 * Return the contained value, if present, otherwise throw an exception
 * to be created by the provided supplier.
 */
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}
​
​
public static void main(String[] args) {
    PersonEntity person = null;
    Optional<PersonEntity> optional = Optional.ofNullable(person);
    System.out.println(optional.orElseThrow(() -> new RuntimeException("this value is null")));
    /*
     * 抛异常:java.lang.RuntimeException: this value is null
     */
}

四、判断是否存在

1、isPresent

isPresent,判断Optional的value是否为EMPTY,为空值返回false,不为空值返回true。

/**
 * Return {@code true} if there is a value present, otherwise {@code false}.
 */
public boolean isPresent() {
    return value != null;
}

// 测试用例
public static void main(String[] args) {
    PersonEntity person = null;
    Optional<PersonEntity> optional = Optional.ofNullable(person);
    System.out.println(optional.isPresent());
    /*
     * 返回结果:false
     */
    
    PersonEntity person2 = new PersonEntity("刘六", 21);
    Optional<PersonEntity> optional2 = Optional.ofNullable(person2);
    System.out.println(optional2.isPresent());
    /*
     * 返回结果:true
     */
}

2、ifPresent

ifPresent,判断Optional的value是否为EMPTY,不为空值则调用Consumer消费型接口的accept方法,否则什么都不做。

/**
 * If a value is present, invoke the specified consumer with the value,
 * otherwise do nothing.
 */
public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

// 测试用例
public static void main(String[] args) {
    PersonEntity person = new PersonEntity("秦七", 21);
    Optional<PersonEntity> optional = Optional.ofNullable(person);
    optional.ifPresent(System.out::println);
    /*
     * 返回结果:PersonEntity(name=秦七, age=21)
     */
    
    PersonEntity person2 = new null;
    Optional<PersonEntity> optional2 = Optional.ofNullable(person2);
    optional2.ifPresent(System.out::println);
    /*
     * 返回结果:
     */
}

五、判断是否相等

1、equals

equals,比较两个Optional对象,指向地址相同为true,不是Optional对象为false,然后在比较两者的value值。

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }

    if (!(obj instanceof Optional)) {
        return false;
    }

    Optional<?> other = (Optional<?>) obj;
    return Objects.equals(value, other.value);
}

2、hashCode

hashCode,获取该Optional对象的hashCode,如果value值为空返回0,不为空则返回Obejct.hashCode()。

如果两个Optional对象的value值相同,那他们的hashCode也是相同。

@Override
public int hashCode() {
    return Objects.hashCode(value);
}

// Objects.hashCode()方法
public static int hashCode(Object o) {
    return o != null ? o.hashCode() : 0;
}

六、其他lambda表达式

1、filter

filter,判断Optional的value是否为EMPTY,不为空值且满足Predicate断言型接口则返回该Optional对象,其他情况均返回空Optional对象。

/**
 * If a value is present, and the value matches the given predicate,
 * return an {@code Optional} describing the value, otherwise return an
 * empty {@code Optional}.
 */
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}

// 测试用例
public static void main(String[] args) {
    PersonEntity person = new PersonEntity("赵八", 28);
    Optional<PersonEntity> optional = Optional.ofNullable(person);
    System.out.println(optional.filter(p -> p.getAge() > 15));
    /*
     * 返回结果:PersonEntity(name=赵八, age=28)
     */
    
    PersonEntity person2 = new PersonEntity("赵八2", 10);
    Optional<PersonEntity> optional2 = Optional.ofNullable(person2);
    System.out.println(optional2.filter(p -> p.getAge() > 15));
    /*
     * 返回结果:Optional.empty
     */
}

2、map

map,判断Optional的value是否为EMPTY,不为空值就调用Function函数型接口,如果结果不为空则返回包含该结果的Optional对象,其他情况均返回空Optional对象。

/**
 * If a value is present, apply the provided mapping function to it,
 * and if the result is non-null, return an {@code Optional} describing the
 * result.  Otherwise return an empty {@code Optional}.
 */
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));
    }
}


public static void main(String[] args) {
    PersonEntity person = new PersonEntity("牛九", 21, null);
    Optional<PersonEntity> optional = Optional.ofNullable(person);
    System.out.println(optional.map(PersonEntity::getName));
    /*
     * 返回结果:Optional[牛九]
     */
    
    PersonEntity person2 = null;
    Optional<PersonEntity> optional2 = Optional.ofNullable(person2);
    System.out.println(optional2.map(PersonEntity::getName));
    /*
     * 返回结果:Optional.empty
     */
}

3、flatMap

flatMap,判断Optional的value是否为EMPTY,不为空值就调用Function函数型接口,如果结果不为空则返回Optional类型返回值,其他情况均返回空Optional对象。

/**
 * If a value is present, apply the provided {@code Optional}-bearing
 * mapping function to it, return that result, otherwise return an empty
 * {@code Optional}.  This method is similar to {@link #map(Function)},
 * but the provided mapper is one whose result is already an {@code Optional},
 * and if invoked, {@code flatMap} does not wrap it with an additional
 * {@code Optional}.
 */
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}


public static void main(String[] args) {
    PersonEntity person = new PersonEntity("石十", 21, null);
    Optional<PersonEntity> optional = Optional.ofNullable(person);
    System.out.println(optional.flatMap(p -> Optional.ofNullable(p.getName())));
    /*
     * 返回结果:Optional[石十]
     */
    
    PersonEntity person2 = null;
    Optional<PersonEntity> optional2 = Optional.ofNullable(person2);
    System.out.println(optional2.flatMap(p -> Optional.ofNullable(p.getName())));
    /*
     * 返回结果:Optional.empty
     */
}

mapflatMap区别:

方法名mapflatMap
方法参数Function<? super T, ? extend U>mapperFunction<? super T, Optional<U>> mapper
mapper结果U,表示一个普通对象Optional,表示Optional对象
过程用ofNullable方法包装U,返回Optional直接返回Optional

七、注意事项

  1. Optional没有实现Serializable接口,就意味着它无法被序列化,所以它不应该用作类的字段。
  2. 只有每当结果不确定时,使用Optional作为返回类型,从某种意义上讲,这是使用Optional的唯一好地方,用java官方的话讲就是:我们的目的是为库方法的返回类型提供一种有限的机制,其中需要一种明确的方式来表示“无结果”,并且对于这样的方法使用null 绝对可能导致错误。
  3. 避免使用Optional.isPresent()来判断Optional的值是否为空,这种方法和null != obj没有区别,也就没有意义。
  4. 避免使用Optional.get()来获取实例对象,因为使用前需要调用Optional.isPresent()来判断,否则会出现NoSuchElementException异常,建议使用orElse()orElseGet()orElseThrow()获得结果。

八、案例实践

1、测试用例

人员实体

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PersonEntity {
    private String id;
    
    private String name;

    private Integer age;

    private DogEntity dog;
}

宠物狗实体

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DogEntity {
    private String id;
    
    private String name;

    private Integer age;
}

伪方法

// 根据id集合获取人员信息
private static List<PersonEntity> selectPerson(List<String> ids) {
    return null;
}

// 根据id集合获取宠物狗信息
private static List<DogEntity> selectDot(List<String> ids) {
    return null;
}

2、获取宠物狗名称

// 方法一:!=null方法
public static String getDogName1(PersonEntity person) {
    if (null != person) {
        DogEntity dog = person.getDog();
        if (null != dog) {
            return dog.getName();
        }
    }
    return "旺财";
}

// 方法二:Optional方法
public static String getDogName2(PersonEntity person) {
    return Optional.ofNullable(person)
        .map(PersonEntity::getDog)
        .map(DogEntity::getName)
        .orElse("旺财");
}

3、获取宠物狗名称集合

// 方法一:普通方法
public static List<String> getDogNameList1(List<String> personIds) {
    List<String> dogNameList = new ArrayList<>();
    List<PersonEntity> personList = selectPerson(personIds);
    if (null == personList || 0 ==  personList.size()) {
        return dogNameList;
    }
    List<String> personNewIds = new ArrayList<>();
    for (int i = 0; i < personList.size(); i++) {
        if (null != personList.get(i)) {
            personNewIds.add(personList.get(i).getName());
        }
    }
    if (null == personNewIds || 0 ==  personNewIds.size()) {
        return dogNameList;
    }
    List<DogEntity> dogList = selectDot(personNewIds);
    for (int i = 0; i < dogList.size(); i++) {
        if (null != dogList.get(i)) {
            dogNameList.add(dogList.get(i).getName());
        }
    }
    return dogNameList;
}
​
// 方法二:Optional方法
public static List<String> getDogNameList2(List<String> personIds) {
    List<String> dogNameList = Optional.ofNullable(selectPerson(personIds))
            .filter(person -> !person.isEmpty())
            .map(pList -> selectDot(pList.stream().map(PersonEntity::getId).collect(Collectors.toList())))
            .map(dList -> dList.stream().map(DogEntity::getName).collect(Collectors.toList()))
            .orElse(new ArrayList<>());
    return dogNameList;
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐