05.JDK8-Optional类

114 阅读5分钟

Optional类

1.目录

2.介绍

Optional是一个没有子类的工具类,Optional是一个可以为null的容器对象。它的作用主要就是为了解决避免Null检查,防止NulPointerException

在Javadoc中是这样描述它的:一个可以为null的容器对象。所以java.util.Optional<T>是一个容器类,它可以保存类型为T的值,T可以是实际Java对象,也可以是null

3.原始解决空指针的案例

代码

@Data 
public class User { 
    private String name; 
    private Address address; 
} 
@Data public class Address { 
    private String province; 
    private String city; 
    private String area; 
}

需求

如果我们需要获取用户所在城市,我们会这么写:

public static String getUserCity(User user) { 
    return user.getAddress().getCity(); 
} 
String city = getUserCity(user);

问题与原始解决方案

这种写法有可能会报NullPointerException,因为user可能为null,user.getAddress()也有可能为null,所以为了解决这个问题,我们会采用这种写法:

public static String getUserCity(User user) { 
    if (user != null) { 
            Address address = user.getAddress(); 
            if (address != null) { 
                return address.getCity(); 
            } 
    } 
    return null; 
}

就问这种写法丑不丑?繁琐不繁琐?为了避免这种丑陋的写法,让丑陋的设计变得优雅,Java8提供了Optional

4.API介绍

定义

public final class Optional<T> {
    /**
     * 如果非空,则为该值;如果为空,则表示没有值存在
     */
    private final T value;
}

从这里可以看出,Optional的本质就是内部存储了一个真实的值T,如果T非空,就为该值,如果为空,则表示该值不存在

构造对象

介绍

Optional的构造函数是private权限的,它对外提供了三个方法用于构造Optional对象

Optional.of(T value)
public static <T> Optional<T> of(T value) { 
    return new Optional<>(value); 
} 
private Optional(T value) { 
    this.value = Objects.requireNonNull(value); 
}

所以Optional.of(T value)是创建一个包含非null值的Optional对象。如果传入的值为null,将抛出NullPointerException异常信息

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

创建一个包含可能为null值的Optional对象。如果传入的值为null,则会创建一个空的Optional对象

Optional.empty()
private static final Optional<?> EMPTY = new Optional<>();

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

创建一个空的Optional对象,表示没有值

检查是否有值

介绍

Optional提供了两个方法用来检查是否有值

isPresent()

用于检查Optional对象是否包含一个非null值,源码如下:

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

示例如下:

User user = null; Optional<User> optional = Optional.ofNullable(user); System.out.println(optional.isPresent()); 
// 结果...... false
ifPresent(Consumer<? super T> action)

该方法用来执行一个操作,该操作只有在Optional包含非null值时才会执行。源码如下:

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

示例如下:

User user = new User("xiaoming");
Optional.ofNullable(user).ifPresent(value-> System.out.println("名字是:" + value.getName()));

获取值

介绍

获取值是Optional中的核心API,Optional为该功能提供了四个方法

get()

get()用来获取Optional对象中的值。如果Optional对象的值为空,会抛出NoSuchElementException异常。源码如下:

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

orElse()用来获取Optional对象中的值,如果值为空,则返回指定的默认值。源码如下:

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

示例如下:

User user = null; 
user = Optional.ofNullable(user).orElse(new User("xiaohong")); 
System.out.println(user); 
// 结果...... User(name=xiaohong, address=null)
orElseGet(Supplier<? extends T> other)

orElseGet()用来获取Optional对象中的值,如果值为空,则通过Supplier提供的逻辑来生成默认值。源码如下:

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

示例如下:

User user = null; 
user = Optional.ofNullable(user).orElseGet(() -> { 
    Address address = new Address("湖南省","长沙市","岳麓区"); 
    return new User("xiaohong",address); 
}); 
System.out.println(user); 
// 结果...... User(name=xiaohong, address=Address(province=湖南省, city=长沙市, area=岳麓区))
orElseThrow(Supplier<? extends X> exceptionSupplier)

orElseThrow()用来获取Optional对象中的值,如果值为空,则通过Supplier提供的逻辑抛出异常。源码如下:

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

示例如下:

User user = null; 
user = Optional.ofNullable(user).orElseThrow(() -> new RuntimeException("用户不存在"));

类型转换

介绍

Optional提供map()和flatMap()用来进行类型转换

map(Function<? super T, ? extends U> mapper)

map()允许我们对Optional对象中的值进行转换,并将结果包装在一个新的Optional对象中。该方法接受一个Function函数,该函数将当前Optional对象中的值映射成另一种类型的值,并返回一个新的Optional对应,这个新的Optional对象中的值就是映射后的值。如果当前Optional对象的值为空,则返回一个空的Optional对象,且Function不会执行,源码如下:

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

比如我们要获取User对象中的name,如下:

User user = new User("xiaolan"); 
String name = Optional.ofNullable(user).map(value -> value.getName()).get(); System.out.println(name); 
// 结果...... xiaolan
flatMap(Function<? super T, Optional<U>> mapper)

flatMap()与map()相似,不同之处在于flatMap()的映射函数返回的是一个Optional对象而不是直接的值,它是将当前Optional对象映射为另外一个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)); 
    } 
}

上面获取 name 的代码如下:

String name = Optional.ofNullable(user).flatMap(value -> Optional.ofNullable(value.getName())).get();

flatMap()内部需要再次封装一个Optional对象,所以flatMap()通常用于在一系列操作中处理嵌套的Optional对象,以避免层层嵌套的情况,使代码更加清晰和简洁

过滤

Optional提供了filter()用于在Optional对象中的值满足特定条件时进行过滤操作,源码如下:

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

filter()接受一个Predicate来对Optional中包含的值进行过滤,如果满足条件,那么还是返回这个Optional;否则返回Optional.empty

常用方法总结