一、Optional概述
Optional是Java 8中新增的一个类,用于解决空指针异常(NullPointerException)问题。Optional类包装了一个对象,并提供了一组方法来处理该对象是否为空的情况,避免了在代码中频繁使用null值的情况。
理解关键: 可以把Optional理解成容器,把对象包裹进Optional容器中进行一系列的判空、映射等操作
二、Optional的用法介绍
1. 构建类方法
Optional.of(T t) : 创建一个 Optional 实例,t 必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):t 可以为 null
源码解析
of和ofNullable
两者都是获取Option实例,并且都是静态的
of 会抛出空指针异常
// 把实例放入Optional容器
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 放入Optional容器时进行判空
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
// 为空的情况下抛出空指针异常
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
ofNullable 进行了判空处理
// 区别与of:为空的情况下返回空的Optional容器
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
验证示例:
@Test
public void of_test() {
User user = null;
Optional<User> optional = Optional.of(user);
System.out.println(user);
}
@Test
public void ofNullable_test() {
User user = null;
Optional<User> optional = Optional.ofNullable(user);
System.out.println(user);
}
2. 获取类方法
T get(): 如果调用对象包含值不为 null,返回该值,否则抛异常
T orElse(T other) :如果有值则将其返回,否则返回指定的 other 对象。
T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由 Supplier 接口实现提供的对象。
T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由 Supplier
源码解析
// 如果值存在,则取出该值,否则抛出异常NoSuchElementException
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
// 如果值存在,则取出该值,否则返回缺省值other
public T orElse(T other) {
return value != null ? value : other;
}
// 如果值存在,则取出该值,否则返回由供应函数supplier产生的结果
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
// 如果值存在,则取出该值,否则返回由供应函数supplier产生的异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
验证示例
@Test
public void orElseGet_test() throws Throwable {
final Optional<String> optional = Optional.ofNullable("2");
System.out.println(optional.get());
System.out.println(optional.orElse("0"));
System.out.println(optional.orElseGet(() -> "0"));
System.out.println(optional.orElseThrow(NullPointerException::new));
}
3. 判断类方法
boolean isPresent() : 判断是否包含对象
void ifPresent(Consumer<? super T> consumer) :如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传给它。
源码解析
// 判断值是否存在,返回布尔值
public boolean isPresent() {
return value != null;
}
// 如果存在值,则使用该值执行给定的操作,否则不执行任何操作。
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
验证示例
@Test
public void presentTest(){
final Optional<String> optional = Optional.ofNullable("2");
System.out.println(optional.isPresent());
optional.ifPresent(System.out::println);
}
4. 过滤类方法
Optional<T> filter(Predicate<? super <T> predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional。
源码解析
// 如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional。
public Optional<T> filter(Predicate<? super T> predicate) {
// 入参预测函数校验
Objects.requireNonNull(predicate);
// 不存在值直接返回this,也就是当前Optional实例
if (!isPresent())
return this;
else
// 值存在,并且匹配预测,返回满足预测的Optional,否则返回空的Optional
return predicate.test(value) ? this : empty();
}
验证示例
@Test
public void filterTest() {
final Optional<Integer> optional = Optional.ofNullable(2);
System.out.println(optional.filter(e -> e > 1).get());
}
5. 映射类方法
<U>Optional<U> map(Function<? super T,? extends U> mapper):如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返回一个空的 Optional 对象
map和flatMap
相同点: 两个方法的返回值都是 Optional 对象!
不同点: 区别在于调用两个方法需要的传入参数(函数式接口)的返回值不同,
map 方法会自动将入参中的函数式接口返回值包装成 Optional 对象,而 flatMap 方法则要求入参中的函数式接口返回值本身就是 Optional 对象。
@Test
public void map_test() {
User user = User.builder().userName("小四").build();
final Optional<String> optional = Optional.ofNullable(user).map(User::getUserName);
final Optional<String> optional1 = Optional.ofNullable(user).flatMap(user1 -> Optional.ofNullable(user1.getUserName()));
System.out.println(optional.get());
System.out.println(optional1.get());
}
三、使用场景
1. 使用Optional优化多层调用
public class Person {
private String name;
private Optional<Company> company;
// ...
}
public class Company {
private String name;
private Optional<Address> address;
// ...
}
public class Address {
private String city;
// ...
}
// 多层调用
Person person = new Person();
if (person != null) {
Company company = person.getCompany();
if (company != null) {
Address address = company.getAddress();
if (address != null) {
String city = address.getCity();
if (city != null) {
System.out.println(city);
}
}
}
}
// 使用Optional优化多层调用
String city = Optional.ofNullable(person)
.flatMap(Person::getCompany)
.flatMap(Company::getAddress)
.map(Address::getCity)
.orElse("unknown");
System.out.println(city);
2. 值非空情况下执行特定逻辑
// 传统写法
String str = null;
if (str != null) {
System.out.println(str.toUpperCase());
}
// 使用Optional优化
Optional<String> optional = Optional.ofNullable(str).ifPresent(s -> System.out.println(s.toUpperCase()));
3. 简化try-catch语句
// 传统写法
String content = "";
File file = new File("filename.txt");
try (Scanner scanner = new Scanner(file)) {
content = scanner.useDelimiter("\\Z").next();
} catch (IOException e) {
e.printStackTrace();
}
// 使用Optional优化
File file = new File("filename.txt");
Optional<String> optional = Optional.empty();
try {
optional = Optional.of(new Scanner(file).useDelimiter("\\Z").next());
} catch (IOException e) {
e.printStackTrace();
}
String content = optional.orElse("");