jdk8-Optional类

1,051 阅读4分钟

Optional简介

Optional 类是jdk8新增的一个新特性,是一个可以为null的容器对象;可以用来解决NullPointerExpection.

Optional实例化

Optional类有3个实例化的方法:

方法名 功能
empty() 创建一个空的Optional对象
of(T t) 创建一个包含t对象的Optional对象;t==null时,抛出NullPointerException异常
ofNullable(T t) 创建一个包含t对象的Optional对象;t==null时,创建一个空的Optional对象

访问Optional对象的值

方法名 功能
get() 如果Optional有值则将其返回,否则抛出异常 NoSuchElementException
orElse(T other) 如果Optional实例有值则将其返回,否则返回orElse方法传入的参数
orElseGet(Supplier<? extends T> other) 与orElse()方法类似,但通过Supplier接口的实现用来生成默认值
orElseThrow(Supplier<? extends X> eother) 如果有值则将其返回,否则抛出supplier接口创建的异常

使用示例如下:

public class OptionalTest {
    public static void main(String[] args) {
        System.out.println("1:" + Optional.ofNullable("test").get());
        System.out.println("2:" + Optional.ofNullable("test").orElse("default"));
        System.out.println("3:" + Optional.ofNullable(null).orElse("default"));
        System.out.println("4:" + Optional.ofNullable(null).orElseGet(() -> "default"));
//    下面两行代码分别抛出NoSuchElementException和NullPointerException
//        System.out.println("5:" + Optional.empty().get());
//        System.out.println("6:" + Optional.empty().orElseThrow(()->new NullPointerException()));

        /**
         * orElseGet/orElseThrow接受一个Supplier参数,如果对象为空,就对执行传入的 Lambda 表达式
         * Supplier是一个函数式接口:无参数有返回值的Lambda表达式
         * 详情参考Lambda表达式和函数式编程 ,这里不多赘述
         */
    }
}

打印结果如下:

1:test
2:test
3:default
4:default

orElse 与 orElseGet区别:
当OptionAl对象不为Empty时,orElse函数依然会执行orElse的方法体,而orElseGet函数并不会执行orElseGet的方法体。

校验Optional是否为空

Optional对象为空时,操作Optional对象可能会抛出异常;校验Optional对象有两个方法:

方法名 功能
isPresent() Optional对象为空时返回false,否则返回true
ifPresent(Consumer<? super T> consumer) 如果Optional实例有值则为其调用consumer,否则不做处理
public class OptionalTest {
    public static void main(String[] args) {
        System.out.println("1:::"+Optional.empty().isPresent());
        /**
         * ifPresent除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式
         * Consumer是一个函数式接口:有参数无返回值的Lambda表达式
         */
        Optional.ofNullable("test").ifPresent((x)->System.out.println("2:::不为空:执行此Lambda表达式"));
        Optional.empty().ifPresent((x)->System.out.println("3:::为空:不执行"));
    }
}

打印结果:

1:::false
2:::不为空:执行此Lambda表达式

转换Optional对象值

方法名 功能
map(Function<? super T, ? extends U> mapper) 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional
flatMap(Function<? super T, Optional> mapper) 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
filter(Predicate<? super T> predicate) 如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional

使用示例如下:

public class OptionalTest {
    public static void main(String[] args) {
        /**
         * 用字符串test初始化一个Optional对象,调用map方法替换Optional的值,再调用orElse方法返回Optional对象值
         */
        System.out.println("1:::" + Optional.ofNullable("test").map(t -> "changed").orElse("default"));
        
        System.out.println("2:::" + Optional.empty().map(t -> "changed").orElse("default"));
        System.out.println("3:::" + Optional.ofNullable("test").flatMap(t -> Optional.of("changed")).orElse("default"));
        System.out.println("4:::" + Optional.of("test").filter(t -> true).orElse("default"));
    }
}

打印结果:

1:::changed
2:::default
3:::changed
4:::test

map(mapper) 与 flatMap(mapper)区别:
功能上基本是一样的,只是最后的返回值不一样。map(mapper)方法中的mapper可以返回任意类型,但是flatMap(mapper)方法中的mapper只能返回Optional类型

Optional链式调用

/**
 * 普通写法
 */
public String getCity(User user)  throws Exception{
        if(user!=null){
            if(user.getAddress()!=null){
                Address address = user.getAddress();
                if(address.getCity()!=null){
                    return address.getCity();
                }
            }
        }
        throw new Excpetion("取值错误"); 
    }
/**
 * Optional写法
 */    
public String getCity(User user) throws Exception{
    return Optional.ofNullable(user)
                   .map(u-> u.getAddress())
                   .map(a->a.getCity())
                   .orElseThrow(()->new Exception("取值错误"));
}

当在进行链式调用时,层级越高,使用Optional时,代码会越简介;而使用if判断Null,则相反。

总结

1.虽然Optional链式调用时,代码很简洁,但是可读性却随之降低;在if嵌套判断不多时,笔者建议还是使用if判断NUll,或者使用3元表达式。【参考阿里开发规范】

2.关于Optional的说明本文均从示例的角度加以阐述。对Optional原理并未说明,原理可直接阅读源码,Optional类源码主要还是函数式编程,需要先了解lambda表达式相关。