ramostear.comramostear.com 谭朝红的技术分享博客

格言 编程是一门技术,也是一门艺术 !

Java 8 Optional源码及案例分析

Java 8 Optional源码及案例分析

java.util.optional是从JDK 8开始引的类,Optional是一个包含了空值(NULL)或非空值(NOT NULL)的对象容器,用于判断方法的返回类型是否有值,Optional的好处是可以避免由于NULL带来的异常情况,如NullPointerException。一般地,如果一个方法的返回类型是Optional,则该方法应该经量避免返回NULL,对应的应该返回一个包含了NULL对象的Optional实例。

提示:本文编写时使用的是JDK 8

Optional源码分析

Optional是一个对象容器,你可以在java.util包中找到该类。接下来,将分析Optional类中的构造器,属性和方法。Optional类的源码和分析如下:

public final class Optional<T> {
    /**
     * EMPTY代表NULL值的Optional对象实例
     */
    private static final Optional<?> EMPTY = new Optional<>();

    /**
     * 泛型类型的对象实例
     */
    private final T value;

    /**
     * 私有的Optional空构造函数
     */
    private Optional() {
        this.value = null;
    }

    /**
     * 返回内部的EMPTY实例
     */
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

    /**
     * 通过value实例化Optional对象,如果value为空,则抛出空指针异常
     */
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 通过value实例化Optional对象,如果value为空,则抛出空指针异常
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    /**
     * 通过value实例化Optional对象,如果value为空,则返回EMPTY,
     * 如果value不为空,则调用Optional::of(value)方法
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * 如果value的值不为空,则返回value,否则抛出NoSuchElementException异常
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * 如果value的值不为空,返回true,否则返回false
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
       * 如果value不为NULL,则使用value调用消费者函数式接口的消费方法Consumer::accept()    
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

    /**
     * 如果存在值,并且值与给定谓词匹配,则返回描述该值的值,否则返回空值
     */
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

    /**
     * 如果存在值,则将提供的映射函数应用于该值,如果结果为非null,则返回描述结果的值。 否则返回空
     */
    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 T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     *如果值存在,则返回该值,否则返回指定的被调用函数的返回值。
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

    /**
     * 如果值存在,则返回该值,否则抛出创建者提供的异常信息
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

    // other code....
}

empty()方法

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

如果明确表示一个持有NULL值的Optional实例,则使用Optional.empty()方法,例如:

Optional nullOpt = Optional.empty();

of()方法

public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}

如果能够明确判断一个对象的值不为NULL时,应该使用Optional.of()方法,例如:

User user = userService.findById(userId);
if(user != null){
    Optional userOptional = Optional.of(user);
}

ofNullable()方法

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

如果无法确认一个对象的值是否为空的时候,应该使用Optional.ofNullable()方法,例如:

User user = userService.findByEmail(userEmail);
Optional userOptional = Optional.ofNullable(user);

get()方法

@NotNull
public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

一般地,get()方法需要先确认value的值不为空后才使用,get()方法需要先校验value存在与否。例如:

User user = userService.findByUsername(username);
if(user != null){
    Optional userOptional = Optional.of(user);
    User value = userOptional.get();
}

isPresent()方法

public boolean isPresent() {
    return value != null;
}

isPresent()方法用于判断value是否存在,如果存在,返回true;如果不存在,返回false。例如:

User user = userService.findById(userId);
boolean exist = Optional.ofNullable(user).isPresent();

Optional<User> uop = userService.findOne(userId);
if(uop.isPresent()){
    return uop.get();
}else{
    return new User();
}

ifPresent()方法

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

顾名思义,如果value的值不为空,则使用value调用消费者函数式接口的消费方法Consumer.accept(),例如:

User user = userService.findById(userId);
Optional op = Optional.ofNullable(user);
op.ifPresent(u->System.out::println);

filter()方法

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

filter()方法用于实现简单的过滤功能,如果Optional容器包含的值不为空,则返回满足过滤条件的值,否则返回empty()函数的返回值。例如:

List<User> list = userService.findAll();
list.forEach(item->{
   Optional.ofNullable(item)
           .filter(user-> user.getStatus == 1)
           .isPresent(user->System.out::println); 
});

map()方法

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));
    }
}

map()方法用于类型转换操作,通过功能函数mapper.apply()对value进行类型映射,重新封装为可空的Optional对象实例,例如:

List<String> list = Arrays.asList("java","jvm","jre","jdk");
Optional<List<String>> listOptional = Optional.of(list);
int size = listOptional.map(List::size).orElse(0);
System.out.println("size = " + size);

output:

size = 4

flatMap()方法

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));
    }
}

与map()方法一样,flatMap()方法也是进行类型映射操作,唯一不同于map()方法的是flatMap()方法中Optional类型返回值直接由外部决定,不需要通过值重新封装为Optional实例。例如:

public class User{
    private String username;

    public Optional<String> getUsername(){
        return Optional.ofNullable(username);
    }

    public User(String username){
        this.username = username;
    }
}
public class TestFlatMapMethod{
    public static void main(String[] args){
        User user = new User("ramostear");
        Optional<User> userOptional = Optional.of(user);

        Optional<Optional<String>> usernameOptional = userOptional.map(User::getUsername);
        //map()方法需要再次封装Optional类型
        Optioanl<String> nameOptional = usernameOptional.orElseThrow(IllegalArgumentException::new);
        String name = nameOptional.orElse("");
        System.out.println(name);

        //flatMap()方法不需要再次封装Optional类型
        String username = userOptional.flatMap(User::getUsername).orElse("");
        System.out.println(username);
    }
}

orElse()方法

public T orElse(T other) {
    return value != null ? value : other;
}

orElse()方法的作用是:当value的值不存在时,提供一个默认的值,例如:

String val1 = null;
String val2 = "default value";
String value = Optional.ofNullable(val1).orElse(val2);

String value2 = Optional.ofNullable(null).orElse("default value");

orElseGet()方法

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}

orElseGet()方法是orElse()方法的升级版本,其好处是可以防止orElse()方法传入NULL值,例如:

String val1 = null;
Supplier<String> fun = ()->"default value";
String value = Optional.ofNullable(val1).orElseGet(fun);

orElseThrow()方法

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

orElseThrow()方法相当于是orElse()方法和orElseGet()方法的增强版,提供了异常处理能力。需要注意的是,orElseThrow()方法处理异常时是抛出而不是捕获。例如:

String username = null;
String name = Optional.ofNullable(username).orElseThrow(IllegalArgumentException::new);

orElse()与orElseGet()的区别

对于不太熟悉Optional的程序员来说,orElse()方法和orElseGet()方法之间的区别并不明显,甚至会觉得这两个方法在功能上是重叠的。然而,这两个方法还是有着本质上的区别,如果不能很好的理解其中的差异,使用这两个方法会严重影响到代码的运行性能。接下来,我们先看一个简单的例子:

public class OptionalExample {

    public static void main(String[] args) {

        String text = null;//"Hello Optional";

        System.out.println("Using Optional.orElseGet() method...");
        String value = Optional.ofNullable(text).orElseGet(OptionalExample::defaultValue);
        System.out.println("orElseGet() method return value = " + value);


        System.out.println("Using Optional.orElse() method...");
        value = Optional.ofNullable(text).orElse(defaultValue());
        System.out.println("orElse() method return value = " + value);

    }


    public static String defaultValue(){
        System.out.println("Getting Default Value...");
        return "Default Value";
    }
}

defaultValue()方法用于返回默认的值,该方法不带任何请求参数。变量text一开始的值为NULL,运行main方法并观察控制台输出:

"C:\Program Files\Java\jdk1.8.0_66\bin\java.exe"...

Using Optional.orElseGet() method...
Getting Default Value...
orElseGet() method return value = Default Value

Using Optional.orElse() method...
Getting Default Value...
orElse() method return value = Default Value

在变量text为NULL的情况下,orElse()方法和orElseGet()方法具有同等的作用,没有任何区别。接下来,将变量text的值修改为“Hello Optional”,运行main方法并观察控制台输出:

"C:\Program Files\Java\jdk1.8.0_66\bin\java.exe"...

Using Optional.orElseGet() method...
orElseGet() method return value = Hello Optional

Using Optional.orElse() method...
Getting Default Value...
orElse() method return value = Hello Optional

当变量text有值的情况下,结果发生了改变。使用orElseGet()方法来判断text的值时,defaultValue()方法不会被执行,因为text值不为空,但使用orElse()方法来判断text值时,无论text的值是否为空,defaultValue()方法都会被执行,在这种情况下,defaultValue()方法就显得非常的冗余且影响代码性能。

为什么为产生这样的区别?原因在于orElse()方法需要提供一个类型变量,在orElse()方法工作之前,就需要确定类型变量的值,这也就是为什么在变量text有值的情况下defaultValue()方法依然被执行的原因;而orElseGet()方法的入参是对象的提供者(Supplier),只有当变量text为空的时候,才会调用对象提供者所提供的具体方法。

总结

本文详细介绍了Java 8 Optional类的基本用法、注意事项以及区别。其中值得注意的是of(),ofNullable()之间的区别,get()的使用条件,map()和flatMap()的区别,orElse和orElseGet()的使用场景。