Optional 是 JDK1.8 中的一个很流弊的新特性,每个接触JAVA的都遇到过 NPE(NullPointerException),1.8中Optional 帮助我们很好的避免了这一现象。
of/empty/ofNullable
User user = null; // user 是一个 空对象
/**
* 源码:
* public static <T> Optional<T> of(T value) { // of会创建一个 实例化一个 Optional
* return new Optional<>(value);
* }
*
* private Optional(T value) { // 检查value是否为null
* this.value = Objects.requireNonNull(value);
* }
*
* public static <T> T requireNonNull(T obj) { // 不做解释了...
* if (obj == null)
* throw new NullPointerException();
* return obj;
* }
*
* 解释:如果对象为Null使用of会抛出java.lang.NullPointerException
*/
Optional<User> op1 = Optional.of(user);
Optional<User> op2 = Optional.empty(); // 看API就知道啥意思了,基本没什么太大卵用
/**
* 源码:
* public static <T> Optional<T> ofNullable(T value) {
* return value == null ? empty() : of(value);
* }
* 解释:如果对象为空就返回 empty() 相反就 调用 of(value);
*/
Optional<User> op3 = Optional.ofNullable(user);
get/isPresent
Optional<User> op = Optional.ofNullable(null); // 创建一个对象为Null的Optional
/**
* 源码:
* public boolean isPresent() {
* return value != null;
* }
* 解释:因为 value == null 源码是 value != null 因此返回false
*/
System.out.println(op.isPresent());
/**
* 源码:
* public T get() {
* if (value == null) {
* throw new NoSuchElementException("No value present");
* }
* return value;
* }
* 解释:如果 value 为空 null 抛出 NoSuchElementException 否则返回 T
*/
System.out.println(op.get());
orElse/orElseGet/orElseThrow
User user = null;
/**
* 源码:
* public T orElseGet(Supplier<? extends T> other) {
* return value != null ? value : other.get();
* }
* 解释:对象为空返回null,否则返回对象
* 注:功能与orElse(T other)类似,不过该方法可选值的获取不是通过参数直接获取,而是通过调用传入的Lambda表达式获取
*/
User u1 = Optional.ofNullable(user).orElseGet(User::new);
System.out.println(u1);//User{id=null, name='null', email='null', age=null}
/**
* 源码:
* public T orElse(T other) {
* return value != null ? value : other;
* }
* 解释:如果 T 为null则返回一个默认值
*/
User u2 = (User) Optional.ofNullable(user).orElse(new User(1L, "lisi", "xxx@qq.com", 22));
System.out.println(u2);//Student{id=1, name='lisi', email='xxx@qq.com', age=22}
/**
* 源码:
* public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
* if (value != null) {
* return value;
* } else {
* throw exceptionSupplier.get();
* }
* }
* 解释:如果T为null那么抛出异常(本宝宝非常喜欢)
*/
User u3 = Optional.ofNullable(user).orElseThrow(() -> new RuntimeException("哈哈,报错了吧"));
System.out.println(u3); //抛出:java.lang.RuntimeException: 哈哈,报错了吧
filter/map
// 可以加if判断条件过滤
String filter = Optional.ofNullable("aadasdsa").filter((value) -> value.length() > 5).get();
System.out.println(filter);
// 大小写转换等等..
String map = Optional.ofNullable("aadasdsa").map(String::toUpperCase).get();
System.out.println(map);
使用map
函数返回对象,使用flatMap
返回Optional
。
Optional转集合
将一个Optional转为List或者Set
public static <T> List<T> toList(Optional<T> option) {
return option.
map(Collections::singletonList).
orElse(Collections.emptyList());
}
或者更传统的写法:
public static <T> List<T> toList(Optional<T> option) {
if (option.isPresent())
return Collections.singletonList(option.get());
else
return Collections.emptyList();
}
但是在java8里,其实只需要这么写:
import static java.util.stream.Collectors.*;
//转为List
List<String> list = collect(opt, toList());
//转为Set
Set<String> set = collect(opt, toSet());
如何正确使用Optional
假设你试图使用Optional
来避免可能出现的NullPointerException
异常,编写了如下代码:
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
接口,这在某些情况下是很重要的(比如你的项目中使用了某些序列化框架),使用了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 user.map(User::getUserName)
.map(String::toUpperCase)
.orElse(null);
总结一下,新的Optional
类让我们可以以函数式编程的方式处理null
值,抛弃了Java 8之前需要嵌套大量if-else
代码块,使代码可读性有了很大的提高。
「真诚赞赏,手留余香」
请我喝杯咖啡?
使用微信扫描二维码完成支付
