Optional 使用
Optional 类描述
- Optional 类所在包: java.util.Optional
- Optional 类声明: public final class Optional extends Object
- Optional 类方法:
方法名称 | 修饰符、返回类型 | 方法描述 |
---|---|---|
empty() | static |
方法描述 |
equals(Object obj) | boolean | 判断其他对象是否等于 Optional。 |
filter(Predicate<? super T> predicate) | Optional |
如果有值并且满足断言条件返回包含该值的 Optional,否则返回空 Optional。 |
get() | T | 如果在这个 Optional 中包含这个值则返回值,否则抛出 NoSuchElementException 异常。 |
hashCode() | int | 返回存在值的哈希码,如果值不存在则返回 0。 |
ifPresent(Consumer<? super T> consumer) | void | 如果值存在则使用该值调用 consumer , 否则不做任何事情。 |
isPresent() | boolean | 如果值存在则方法会返回 true,否则返回 false。 |
flatMap(Function<? super T,Optional> mapper) | Optional | 如果值存在,返回基于 Optional 包含的映射方法的值,否则返回一个空的 Optional。 |
map(Function<? super T,? extends U> mapper) | Optional | 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。 |
of(T value) | static |
返回一个指定非 null 值的 Optional。 |
ofNullable(T value) | static |
果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。 |
orElse(T other) | T | 如果该值存在就直接返回, 否则返回指定的其它值。 |
orElseGet(Supplier<? extends T> other) | T | 如果该值存在就返回值,否则触发 other,并返回 other 调用的结果。 |
orElseThrow(Supplier<? extends X> exceptionSupplier) | 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常。 | |
toString() | String | 返回一个 Optional 的非空字符串,用来调试。 |
创建Opional
对象
Optional
类提供类三个方法用于实例化一个Optional
对象,它们分别为empty()
、of()
、ofNullable()
,这三个方法都是静态方法,可以直接调用。
empty()
empty()
方法用于创建一个没有值的Optional
对象:
Optional<String> emptyOpt = Optional.empty();
empty()
方法创建的对象没有值,如果对emptyOpt
变量调用isPresent()
方法会返回false
,调用get()
方法抛出NullPointerException
异常。
of()
of()
方法使用一个非空的值创建Optional
对象:
String str = "Hello World";
Optional<String> notNullOpt = Optional.of(str);
ofNullable()
ofNullable()
方法接收一个可以为null
的值:
Optional<String> nullableOpt = Optional.ofNullable(str);
如果str
的值为null
,得到的nullableOpt
是一个没有值的Optional
对象。
Optional
方法的方法
提取Optional
对象中的值
如果我们要获取User
对象中的roleId
属性值,常见的方式是直接获取
String roleId = null;
if (user != null) {
roleId = user.getRoleId();
}
使用Optional
中提供的map()
方法可以以更简单的方式实现
Optional<User> userOpt = Optional.ofNullable(user);
Optional<String> roleIdOpt = userOpt.map(User::getRoleId);
map()
方法与Stream API中的map()
一样,类似于映射操作,将原始类型映射为一个新的类型。
使用orElse()
方法获取值
Optional
类还包含其他方法用于获取值,这些方法分别为:
orElse()
:如果有值就返回,否则返回一个给定的值作为默认值;orElseGet()
:与orElse()
方法作用类似,区别在于生成默认值的方式不同。该方法接受一个Supplier<? extends T>
函数式接口参数,用于生成默认值;orElseThrow()
:与前面介绍的get()
方法类似,当值为null
时调用这两个方法都会抛出NullPointerException
异常,区别在于该方法可以指定抛出的异常类型。
下面来看看这三个方法的具体用法:
此外,Optional
类还提供了一个ifPresent()
方法,该方法接收一个Consumer<? super T>
函数式接口,可以对值进行一些操作:
Optional<String> strOpt = Optional.of("Hello World");
strOpt.ifPresent(System.out::println);
使用filter()
方法过滤
filter()
方法可用于判断Optional
对象是否满足给定条件,一般用于条件过滤:
Optional<String> optional = Optional.of("lw900925@163.com");
optional = optional.filter(str -> str.contains("164"));
在上面的代码中,如果filter()
方法中的Lambda表达式成立,filter()
方法会返回当前Optional
对象值,否则,返回一个值为空的Optional
对象。
如何正确使用Optional
Optional<User> userOpt = Optional.ofNullable(user);
if (userOpt.isPresent()) {
User user = userOpt.get();
// do something...
} else {
// do something...
}
说实话,这样的写法跟传统的if
语句判断空值没有任何区别,没有起到Optional
的正真作用(中枪的同学举手):
if (user != null) {
// do something...
} else {
// do something...
}
所以,当我们从之前版本切换到Java 8的时候,不应该还按照以前的思维方式处理null
值,Java 8提倡函数式编程,新增的许多API都可以用函数式编程表示,Optional
类也是其中之一。这里有几条关于Optional
使用的建议:
- 尽量避免在程序中直接调用
Optional
对象的get()
和isPresent()
方法; - 避免使用
Optional
类型声明实体类的属性;
第一条建议中直接调用get()
方法是很危险的做法,如果Optional
的值为空,那么毫无疑问会抛出NullPointerException
异常,而为了调用get()
方法而使用isPresent()
方法作为空值检查,这种做法与传统的用if
语句块做空值检查没有任何区别。
第二条建议避免使用Optional
作为实体类的属性,它在设计的时候就没有考虑过用来作为类的属性,可以查看Optional
的源代码,你会发现它没有实现java.io.Serializable
接口,也就是说如果你用到一些orm框架的二级缓存,使用Optional
作为实体类的属性没法被序列化。
下面我们通过一些例子讲解Optional
的正确用法:
正确创建Optional
对象
上面提到创建Optional
对象有三个方法,empty()
方法比较简单,没什么特别要说明的。主要是of()
和ofNullable()
方法。当你很确定一个对象不可能为null
的时候,应该使用of()
方法,否则,尽可能使用ofNullable()
方法,比如:
public static void method(Role role) {
// 当Optional的值通过常量获得或者通过关键字new初始化,可以直接使用of()方法
Optional<String> strOpt = Optional.of("Hello World");
Optional<User> userOpt = Optional.of(new User());
// 方法参数中role值不确定是否为null,使用ofNullable()方法创建
Optional<Role> roleOpt = Optional.ofNullable(role);
}
orElse()
方法的使用
return str != null ? str : "Hello World"
上面的代码表示判断字符串str
是否为空,不为空就返回,否则,返回一个常量。使用Optional
类可以表示为:
return strOpt.orElse("Hello World")
简化if-else
User user = ...
if (user != null) {
String userName = user.getUserName();
if (userName != null) {
return userName.toUpperCase();
} else {
return null;
}
} else {
return null;
}
上面的代码可以简化成:
User user = ...
Optional<User> userOpt = Optional.ofNullable(user);
return userOpt.map(User::getUserName)
.map(String::toUpperCase)
.orElse(null);
再比如判断用户名不能重复的逻辑,根据用户名从数据库中查询一个用户,如果不为null就抛出异常告诉前端用户已存在:
User existUser = userDAO.findById(user.getUsername());
if (existUser != null) {
throw new AppException("用户名已存在");
}
可以简写为:
User user = userDAO.findById(user.getId());
Optional.ofNullable(user).ifPresent(it -> throw new AppException("用户名已存在"));
总结一下,新的Optional
类让我们可以以函数式编程的方式处理null
值而不用嵌套很多if-else
逻辑。