前言: 我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅
我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了
Optional
if (user.isPresent()) {
return user.getOrders();
} else {
return Collections.emptyList();
}
那么不得不说我们的思维仍然是在原地踏步, 只是本能的认为它不过是 User 实例的包装, 这与我们之前写成
User user = .....
if (user != null) {
return user.getOrders();
} else {
return Collections.emptyList();
}
实质上是没有任何分别. 这就是我们将要讲到的使用好 Java 8 Optional 类型的正确姿势.
在里约奥运之时, 新闻一再提起五星红旗有问题, 可是我怎么看都看不出来有什么问题, 后来才道是小星星膜拜中央的姿势不对. 因此我们千万也别对自己习以为常的事情觉得理所当然, 丝毫不会觉得有何不妥, 换句话说也就是当我们切换到 Java 8 的 Optional 时, 不能继承性的对待过往 null 时的那种思维, 应该掌握好新的, 正确的使用 Java 8 Optional 的正确姿势.
直白的讲, 当我们还在以如下几种方式使用 Optional 时, 就得开始检视自己了
调用 isPresent() 方法时
调用 get() 方法时
Optional 类型作为类/实例属性时
Optional 类型作为方法参数时
isPresent() 与 obj != null 无任何分别, 我们的生活依然在步步惊心. 而没有 isPresent() 作铺垫的 get() 调用在 IntelliJ IDEA 中会收到告警
Reports calls to Java.util.Optional.get() without first checking with a isPresent() call if a value is available. If the Optional does not contain a value, get() will throw an exception. (调用 Optional.get() 前不事先用 isPresent() 检查值是否可用. 假如 Optional 不包含一个值, get() 将会抛出一个异常)
把 Optional 类型用作属性或是方法参数在 IntelliJ IDEA 中更是强力不推荐的
Reports any uses of Java.util.Optional
所以 Optional 中我们真正可依赖的应该是除了 isPresent() 和 get() 的其他方法:
public Optional map(Function mapper)
public T orElse(T other)
public T orElseGet(Supplier other)
public void ifPresent(Consumer consumer)
public Optional
public Optional flatMap(Function> mapper)
public
我略有自信的按照它们大概使用频度对上面的方法排了一下序.
先又不得不提一下 Optional 的三种构造方式: Optional.of(obj), Optional.ofNullable(obj) 和明确的 Optional.empty()
Optional.of(obj): 它要求传入的 obj 不能是 null 值的, 否则还没开始进入角色就倒在了 NullPointerException 异常上了.
Optional.ofNullable(obj): 它以一种智能的, 宽容的方式来构造一个 Optional 实例. 来者不拒, 传 null 进到就得到 Optional.empty(), 非 null 就调用 Optional.of(obj).
那是不是我们只要用 Optional.ofNullable(obj) 一劳永逸, 以不变应二变的方式来构造 Optional 实例就行了呢? 那也未必, 否则 Optional.of(obj) 何必如此暴露呢, 私有则可?
我本人的观点是:
1. 当我们非常非常的明确将要传给 Optional.of(obj) 的 obj 参数不可能为 null 时, 比如它是一个刚 new 出来的对象(Optional.of(new User(...))), 或者是一个非 null 常量时;
2. 当想为 obj 断言不为 null 时, 即我们想在万一 obj 为 null 立即报告 NullPointException 异常, 立即修改, 而不是隐藏空指针异常时, 我们就应该果断的用 Optional.of(obj) 来构造 Optional 实例, 而不让任何不可预计的 null 值有可乘之机隐身于 Optional 中.
现在才开始怎么去使用一个已有的 Optional 实例, 假定我们有一个实例 Optional
存在即返回, 无则提供默认值
return user.orElse(null); //而不是 return user.isPresent() ? user.get() : ull;
return user.orElse(UNKNOWN_USER);
存在即返回, 无则由函数来产生
return user.orElseGet(() -> fetchAUserFromDatabase()); //而不要 return user.isPresent() ? user: fetchAUserFromDatabase();
存在才对它做点什么
user.ifPresent(System.out::println);
//而不要下边那样
if (user.isPresent()) {
System.out.println(user.get());
}
map 函数隆重登场
当 user.isPresent() 为真, 获得它关联的 orders, 为假则返回一个空集合时, 我们用上面的 orElse, orElseGet 方法都乏力时, 那原本就是 map 函数的责任, 我们可以这样一行
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())
//上面避免了我们类似 Java 8 之前的做法
if(user.isPresent()) {
return user.get().getOrders();
} else {
return Collections.emptyList();
}
map 是可能无限级联的, 比如再深一层, 获得用户名的大写形式
return user.map(u -> u.getUsername())
.map(name -> name.toUpperCase())
.orElse(null);
这要搁在以前, 每一级调用的展开都需要放一个 null 值的判断
User user = .....
if(user != null) {
String name = user.getUsername();
if(name != null) {
return name.toUpperCase();
} else {
return null;
}
} else {
return null;
}
针对这方面 Groovy 提供了一种安全的属性/方法访问操作符 ?.
user?.getUsername()?.toUpperCase();
Swift 也有类似的语法, 只作用在 Optional 的类型上.
用了 isPresent() 处理 NullPointerException 不叫优雅, 有了 orElse, orElseGet 等, 特别是 map 方法才叫优雅.
其他几个, filter() 把不符合条件的值变为 empty(), flatMap() 总是与 map() 方法成对的, orElseThrow() 在有值时直接返回, 无值时抛出想要的异常.
一句话小结: 使用 Optional 时尽量不直接调用 Optional.get() 方法, Optional.isPresent() 更应该被视为一个私有方法, 应依赖于其他像 Optional.orElse(), Optional.orElseGet(), Optional.map() 等这样的方法.
最后,最好的理解 Java 8 Optional 的方法莫过于看它的源代码 Java.util.Optional, 阅读了源代码才能真真正正的让你解释起来最有底气, Optional 的方法中基本都是内部调用 isPresent() 判断, 真时处理值, 假时什么也不做.
文章出自:http://qh.itpxw.cn/peixun/software/202191082.html
文章标题:秒懂 Java8 Optional 的正确使用姿势
免责声明:本站文章均由入驻起航学习网的会员所发或者网络转载,所述观点仅代表作者本人,不代表起航学习网立场。如有侵权或者其他问题,请联系举报,必删。侵权投诉
IT培训网 访问该机构站点 报名留言 加为好友 用户等级:注册会员
用户级别:10
机构名称:IT培训网
联 系 人:罗老师
联系电话:13783581536
联系手机:13783581536
在线客服:
在 线 QQ:
电子邮件:
网站域名:http://www.itpxw.cn
注册时间:2016-07-18 11:07
最后登录:2024-02-20 13:02
Java定义方法的格式是什么?IT培训网小编来告诉大家。所谓方法...
大家在Java教程中会学到关于Java消息推送的知识,那么,Java消息...
常用的Java日期格式转换有哪些?IT培训网小编来告诉大家。 1...
Java创建对象数组的方法是什么?IT培训网小编来告诉大家。Ja...