介绍
是什么,为什么,做什么
Optional 类是 JDK 8 新增的特性,目的是为了对对象的空指针异常进行优雅的处理。
特点
首先通过查看 Optional 类的代码,可以看到 Optional 类是 final 修饰的,是一个不可变类。即是,一、它不能被继承;二、Optional 对象创建后,是不可修改的。
public final class Optional<T> {
...
}
Optional 类还有一个成员变量 value,即是真正我们所要处理的对象。同样是 final 修饰,不可变。
private final T value;
个人理解
以面向对象的角度来做个比喻:
- 直接处理对象:如果一个对象可能为空,为了避免空指针异常,我会在调用这个对象的方法的时候,先进行一个 if 判断,判断对象不为空之后,再进行方法调用,如果这时候是有多个层次的调用,并且每一层都有可能为空的时候,就会让代码嵌套了很多层的 if ,又臭又长。这不是我想要的。
- 使用 Optional :Optional 就像是一个盒子,将我们想要操作的对象包装起来(成员变量 value 即是这个对象),我们通过 Optional 操作对象,如果对象不为空,操作如常;如果对象为空,Optional 类的代码会让我们在调用的时候更加优雅,不用显式地做 if 判断。
API
构造对象
Optional 的构造函数是私有的,意味着不能直接通过 new 创建 Optional 对象。
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
Optional 的构造方法有 2 个:of()
、ofNullable()
,都是静态方法:
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public static<T> Optional<T> empty() {
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
private static final Optional<?> EMPTY = new Optional<>();
两个构造方法如何选用,从方法名就可以看出一二:如果所包装的对象绝对不为空,则选择 of()
方法创建 Optional 对象;如果所包装的对象可能为空,则选择 ofNullable()
方法创建 Optional 对象。
我自己在使用 Optional 时,绝大部分时候用的都是
ofNullable()
来进行创建的,因为毕竟 Optional 主要就是为了处理空指针嘛。少数情况下,对象绝对不为空,但我需要使用 Optional 的 API ,我就用of()
来创建。
处理 value
get
获取 value 对象
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
isPresent
判断 value 是否存在
public boolean isPresent() {
return value != null;
}
ifPresent
value 如果存在,调用一个方法
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
fliter
value 如果存在,调用一个判断方法对 value 进行判断,true 则返回原 Optional 对象,false 则返回空 Optional 对象
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
map
value 如果存在,调用一个方法对 value 进行处理,然后将处理之后的 value 值放到一个新的 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));
}
}
flatMap
跟 map 方法类似,但是没有将处理之后的 value 值封装到 Optional 对象中,但方法声明中的参数要求返回的是 Optional<U>
对象,所以比起 map 方法,需要自己手动将处理之后的 value 值进行封装返回
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));
}
}
orElse
这个跟 get 方法类似,同样是取 value 的方法,不同的是,如果 value 为空,则返回方法参数中 other 这个对象
public T orElse(T other) {
return value != null ? value : other;
}
orElseGet
与 orElse 方法类似,不同的是参数是函数式接口,相比 orElse 更加灵活,可以写逻辑根据不同情况返回不同的 value 类型的对象
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
与 orElse 不同的还有一点,如果 orElse 参数中的对象也是由方法返回,当 value 为空时,orElse 和 orElseGet 没有区别,当 value 不为空时,orElse 参数中的方法会执行,orElseGet 方法中的方法不会执行,后者性能会高一点。
orElseThrow
与 orElse 类似,不同的是当 value 为空时,会抛出参数中定制的异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
代码示例
User 类
public class User {
private String name;
private String address;
public User() {}
public User(String name, String address) {
this.name = name;
this.address = address;
}
// getter & setter & toString
}
of / ofNullable 示例
public static void main(String[] args) {
User user1 = null;
// 这里会抛出空指针异常
Optional<User> optional1 = Optional.of(user1);
User user2 = new User();
// 正常构造
Optional<User> optional2 = Optional.of(user2);
User user3 = null;
// 正常构造,optioinal3的value为null
Optional<User> optional3 = Optional.ofNullable(user3);
}
isPresent / ifPresent / get 示例
public static void main(String[] args) {
// optionalConstructor();
User user = new User();
user.setName("Jack");
Optional<User> optional = Optional.ofNullable(user);
// isPresent
System.out.println(optional.isPresent());
// ifPresent
optional.ifPresent((value)-> value.setAddress("guangzhou"));
System.out.println(optional.get());
}
控制台打印:
true
User{name='Jack', address='guangzhou'}
filter 示例
User user1 = new User("Jack", "guangzhou");
User user2 = new User("Mary", "beijing");
Optional<User> optional1 = Optional.ofNullable(user1).filter((value) -> "guangzhou".equals(value.getAddress()));
System.out.println(optional1.get());
Optional<User> optional2 = Optional.ofNullable(user2).filter((value) -> "guangzhou".equals(value.getAddress()));
System.out.println(optional2);
控制台打印:
User{name='Jack', address='guangzhou'}
Optional.empty
可以看到,由于 user2 的 address 不是 guangzhou ,所以 optional2 中的 value 是空的。
map / flatMap 示例
User user1 = new User("Jack", "guangzhou");
User user2 = new User("Mary", "beijing");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
Optional<List<String>> optional1 = Optional.ofNullable(list).map((value) -> {
List<String> addressList = new ArrayList<>(value.size());
for (User user : value) {
addressList.add(user.getAddress());
}
return addressList;
});
System.out.println(optional1.get());
Optional<List<String>> optional2 = Optional.ofNullable(list).flatMap((value) -> {
List<String> nameList = new ArrayList<>(value.size());
for (User user : value) {
nameList.add(user.getName());
}
return Optional.ofNullable(nameList);
});
System.out.println(optional2.get());
控制台输出:
[guangzhou, beijing]
[Jack, Mary]
map 是对原来的 value 进行处理映射,然后自动将返回的对象包装到 optional 对象中返回。
flatMap 需要我们手动将 nameList 进行包装再返回。
public class OptionalTest {
public static void main(String[] args) {
User nullUser = null;
User user1 = Optional.ofNullable(nullUser).orElse(getUser());
System.out.println(user1);
User user2 = Optional.ofNullable(nullUser).orElseGet(OptionalTest::getUser);
System.out.println(user2);
Optional.ofNullable(nullUser).orElseThrow(()-> new RuntimeException("User 为空!"));
}
private static User getUser() {
return new User("nobody", "default");
}
}
控制台输出:
User{name='nobody', address='default'}
User{name='nobody', address='default'}
Exception in thread "main" java.lang.RuntimeException: User 为空!
附录:示例代码全文
public class OptionalTest {
public static void main(String[] args) {
optionalConstructor();
isPresentAndIfPresent();
filter();
mapAndFlatMap();
orElse();
}
private static void orElse() {
User nullUser = null;
User user1 = Optional.ofNullable(nullUser).orElse(getUser());
System.out.println(user1);
User user2 = Optional.ofNullable(nullUser).orElseGet(OptionalTest::getUser);
System.out.println(user2);
Optional.ofNullable(nullUser).orElseThrow(()-> new RuntimeException("User 为空!"));
}
private static User getUser() {
return new User("nobody", "default");
}
private static void mapAndFlatMap() {
User user1 = new User("Jack", "guangzhou");
User user2 = new User("Mary", "beijing");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
Optional<List<String>> optional1 = Optional.ofNullable(list).map((value) -> {
List<String> addressList = new ArrayList<>(value.size());
for (User user : value) {
addressList.add(user.getAddress());
}
return addressList;
});
System.out.println(optional1.get());
Optional<List<String>> optional2 = Optional.ofNullable(list).flatMap((value) -> {
List<String> nameList = new ArrayList<>(value.size());
for (User user : value) {
nameList.add(user.getName());
}
return Optional.ofNullable(nameList);
});
System.out.println(optional2.get());
}
private static void filter() {
User user1 = new User("Jack", "guangzhou");
User user2 = new User("Mary", "beijing");
Optional<User> optional1 = Optional.ofNullable(user1).filter((value) -> "guangzhou".equals(value.getAddress()));
System.out.println(optional1.get());
Optional<User> optional2 = Optional.ofNullable(user2).filter((value) -> "guangzhou".equals(value.getAddress()));
System.out.println(optional2);
}
private static void isPresentAndIfPresent() {
User user = new User();
user.setName("Jack");
Optional<User> optional = Optional.ofNullable(user);
// isPresent
System.out.println(optional.isPresent());
// ifPresent
optional.ifPresent((value) -> value.setAddress("guangzhou"));
System.out.println(optional.get());
}
private static void optionalConstructor() {
User user1 = null;
// 这里会抛出空指针异常
Optional<User> optional1 = Optional.of(user1);
User user2 = new User();
// 正常构造
Optional<User> optional2 = Optional.of(user2);
User user3 = null;
// 正常构造,optioinal3的value为null
Optional<User> optional3 = Optional.ofNullable(user3);
}
}