如何更好地管理人使用Java 8的Optional

java(10)
新版本的Java,比如引入了一个新的类。Optional类的Javadoc描述如下:
这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
本文会逐个探讨Optional类包含的方法,并通过一两个示例展示如何使用。
&&&&&&&&&&& 为非null的值创建一个Optional。
of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。
//调用工厂方法创建Optional实例
Optional&String& name = Optional.of(&Sanaulla&);
//传入参数为null,抛出NullPointerException.
Optional&String& someNull = Optional.of(null);
ofNullable
为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。
ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况。示例如下:
//下面创建了一个不包含任何值的Optional实例
//例如,值为'null'
Optional empty = Optional.ofNullable(null);
非常容易理解
如果值存在返回true,否则返回false。
类似下面的代码:
//isPresent方法用来检查Optional实例中是否包含值
if (name.isPresent()) {
//在Optional实例内调用get()返回已存在的值
System.out.println(name.get());//输出Sanaulla
如果Optional有值则将其返回,否则抛出NoSuchElementException。
上面的示例中,get方法用来得到Optional实例中的值。下面我们看一个抛出NoSuchElementException的例子:
//执行下面的代码会输出:No value present
//在空的Optional实例上调用get(),抛出NoSuchElementException
System.out.println(empty.get());
} catch (NoSuchElementException ex) {
System.out.println(ex.getMessage());
如果Optional实例有值则为其调用consumer,否则不做处理
要理解ifPresent方法,首先需要了解。简答地说,Consumer类包含一个抽象方法。该抽象方法对传入的值进行处理,但没有返回值。支持不用接口直接通过传入参数。
如果Optional实例有值,调用ifPresent()可以接受接口段或lambda表达式。类似下面的代码:
//ifPresent方法接受lambda表达式作为参数。
//lambda表达式对Optional的值调用consumer进行处理。
name.ifPresent((value) -& {
System.out.println(&The length of the value is: & + value.length());
如果有值则将其返回,否则返回指定的其它值。
如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。示例如下:
//如果值不为null,orElse方法返回Optional实例的值。
//如果为null,返回传入的消息。
//输出:There is no value present!
System.out.println(empty.orElse(&There is no value present!&));
//输出:Sanaulla
System.out.println(name.orElse(&There is some value!&));
orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受的实现用来生成默认值。示例如下:
//orElseGet与orElse方法类似,区别在于orElse传入的是默认值,
//orElseGet可以接受一个lambda表达式生成默认值。
//输出:Default Value
System.out.println(empty.orElseGet(() -& &Default Value&));
//输出:Sanaulla
System.out.println(name.orElseGet(() -& &Default Value&));
orElseThrow
如果有值则将其返回,否则抛出supplier接口创建的异常。
在orElseGet方法中,我们传入一个。然而,在orElseThrow中我们可以传入一个lambda表达式或方法,如果值不存在来抛出异常。示例如下:
//orElseThrow与orElse方法类似。与返回默认值不同,
//orElseThrow会抛出lambda表达式或方法生成的异常
empty.orElseThrow(ValueAbsentException::new);
} catch (Throwable ex) {
//输出: No value present in the Optional instance
System.out.println(ex.getMessage());
ValueAbsentException定义如下:
class ValueAbsentException extends Throwable {
public ValueAbsentException() {
public ValueAbsentException(String msg) {
super(msg);
public String getMessage() {
return &No value present in the Optional instance&;
map方法文档说明如下:
如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
map方法用来对Optional实例的值执行一系列操作。通过一组实现了Function接口的lambda表达式传入操作。如果你不熟悉Function接口,可以参考我的。map方法示例如下:
//map方法执行传入的lambda表达式参数对Optional实例的值进行修改。
//为lambda表达式的返回值创建新的Optional实例作为map方法的返回值。
Optional&String& upperName = name.map((value) -& value.toUpperCase());
System.out.println(upperName.orElse(&No value found&));flatMap
如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。
参照map函数,使用flatMap重写的示例如下:
//flatMap与map(Function)非常类似,区别在于传入方法的lambda表达式的返回类型。
//map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional。
//但flatMap方法中的lambda表达式返回值必须是Optionl实例。
upperName = name.flatMap((value) -& Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse(&No value found&));//输出SANAULLAfilter
filter个方法通过传入限定条件对Optional实例的值进行过滤。文档描述如下:
如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
读到这里,可能你已经知道如何为filter方法传入一段代码。是的,这里可以传入一个lambda表达式。对于filter函数我们应该传入实现了Predicate接口的lambda表达式。如果你不熟悉Predicate接口,可以参考。
现在我来看看filter的各种用法,下面的示例介绍了满足限定条件和不满足两种情况:
//filter方法检查给定的Option值是否满足某些条件。
//如果满足则返回同一个Option实例,否则返回空Optional。
Optional&String& longName = name.filter((value) -& value.length() & 6);
System.out.println(longName.orElse(&The name is less than 6 characters&));//输出Sanaulla
//另一个例子是Optional值不满足filter指定的条件。
Optional&String& anotherName = Optional.of(&Sana&);
Optional&String& shortName = anotherName.filter((value) -& value.length() & 6);
//输出:name长度不足6字符
System.out.println(shortName.orElse(&The name is less than 6 characters&));
以上,我们介绍了Optional类的各个方法。下面通过一个完整的示例对用法集中展示:
public class OptionalDemo {
public static void main(String[] args) {
//创建Optional实例,也可以通过方法返回值得到。
Optional&String& name = Optional.of(&Sanaulla&);
//创建没有值的Optional实例,例如值为'null'
Optional empty = Optional.ofNullable(null);
//isPresent方法用来检查Optional实例是否有值。
if (name.isPresent()) {
//调用get()返回Optional值。
System.out.println(name.get());
//在Optional实例上调用get()抛出NoSuchElementException。
System.out.println(empty.get());
} catch (NoSuchElementException ex) {
System.out.println(ex.getMessage());
//ifPresent方法接受lambda表达式参数。
//如果Optional值不为空,lambda表达式会处理并在其上执行操作。
name.ifPresent((value) -& {
System.out.println(&The length of the value is: & + value.length());
//如果有值orElse方法会返回Optional实例,否则返回传入的错误信息。
System.out.println(empty.orElse(&There is no value present!&));
System.out.println(name.orElse(&There is some value!&));
//orElseGet与orElse类似,区别在于传入的默认值。
//orElseGet接受lambda表达式生成默认值。
System.out.println(empty.orElseGet(() -& &Default Value&));
System.out.println(name.orElseGet(() -& &Default Value&));
//orElseThrow与orElse方法类似,区别在于返回值。
//orElseThrow抛出由传入的lambda表达式/方法生成异常。
empty.orElseThrow(ValueAbsentException::new);
} catch (Throwable ex) {
System.out.println(ex.getMessage());
//map方法通过传入的lambda表达式修改Optonal实例默认值。
//lambda表达式返回值会包装为Optional实例。
Optional&String& upperName = name.map((value) -& value.toUpperCase());
System.out.println(upperName.orElse(&No value found&));
//flatMap与map(Funtion)非常相似,区别在于lambda表达式的返回值。
//map方法的lambda表达式返回值可以是任何类型,但是返回值会包装成Optional实例。
//但是flatMap方法的lambda返回值总是Optional类型。
upperName = name.flatMap((value) -& Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse(&No value found&));
//filter方法检查Optiona值是否满足给定条件。
//如果满足返回Optional实例值,否则返回空Optional。
Optional&String& longName = name.filter((value) -& value.length() & 6);
System.out.println(longName.orElse(&The name is less than 6 characters&));
//另一个示例,Optional值不满足给定条件。
Optional&String& anotherName = Optional.of(&Sana&);
Optional&String& shortName = anotherName.filter((value) -& value.length() & 6);
System.out.println(shortName.orElse(&The name is less than 6 characters&));
上述代码输出如下:
No value present
The length of the value is: 8
There is no value present!
Default Value
No value present
in the Optional instance
The name is
less than 6 characters
原文链接:
译文链接:
[ 转载请保留原文出处、译者和译文链接。]
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:20787次
排名:千里之外
原创:16篇
转载:13篇
(1)(2)(1)(1)(3)(4)(2)(2)(1)(1)(9)(1)(1)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'Java 8的Optional使用方式 -解道Jdon
& & & &&& & &
  Optional可以避免空指针错误NullPointerExceptions,但是使用时有一定规则遵循。如果没有这些设计模式会影响大量类,导致比较差的可读性。
Optional只用在返回类型
Optional不作为参数也不作为字段,只适合作为返回类型使用,不应该到处使用造成Optional泄漏。
不只是简单调用get()
Optional强大是在于其值可以为空,那么检查是否为空就变得很重要,如果不调用isPresent()就直接简单调用get()也会导致空指针错误。
更灵活方式
在get()之前使用isPresent() 检查:
但是还有更灵活方式,你使用orElse方法在其值为空时指定一个替换值:
或者使用orElseGet ,当值为空时,调用指定的方法获得值:
上述代码中,当Optional值为空时,执行createNewKey()方法创建。
| 网站地图 | 设为首页java8(3)
我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了
Optional&User& user = ……
if (user.isPresent()) {
return user.getOrders();
return Collections.emptyList();
那么不得不说我们的思维仍然是在原地踏步, 只是本能的认为它不过是 User 实例的包装, 这与我们之前写成
User user = …..
if (user != null) {
return user.getOrders();
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&T&, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or mon.base.Optional as the type for a field or a parameter. Optional was designed to provide a limited
mechanism for library method return types where there needed to be a clear way to represent “no result”. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not. (使用任何像 Optional
的类型作为字段或方法参数都是不可取的. Optional 只设计为类库方法的, 可明确表示可能无值情况下的返回类型. Optional 类型不可被序列化, 用作字段类型会出问题的)
所以 Optional 中我们真正可依赖的应该是除了&isPresent()&和&get()&的其他方法:
public&U& Optional&U& map(Function&? super T, ? extends U& mapper)
public T orElse(T other)
public T orElseGet(Supplier&? extends T& other)
public void ifPresent(Consumer&? super T& consumer)
public Optional&T& filter(Predicate&? super T& predicate)
public&U& Optional&U& flatMap(Function&? super T, Optional&U&& mapper)
public &X extends Throwable& T orElseThrow(Supplier&? extends X& exceptionSupplier) throws X
我略有自信的按照它们大概使用频度对上面的方法排了一下序.
先又不得不提一下 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&User& user, 下面是几个普遍的, 应避免&if(user.isPresent()) { ... } else { ... }&几中应用方式.
存在即返回, 无则提供默认值
return&user.orElse(null);&&
return&user.orElse(UNKNOWN_USER);
存在即返回, 无则由函数来产生
return&user.orElseGet(()&-&&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())
if(user.isPresent())&{
&&return&user.get().getOrders();
&&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;
&&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 的方法莫过于看它的源代码,
阅读了源代码才能真真正正的让你解释起来最有底气, Optional 的方法中基本都是内部调用 &isPresent()&判断, 真时处理值, 假时什么也不做.
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:197339次
积分:2831
积分:2831
排名:第13688名
原创:72篇
转载:99篇
评论:12条
(7)(2)(1)(2)(3)(6)(1)(9)(11)(1)(2)(2)(9)(6)(5)(13)(1)(3)(1)(1)(9)(11)(18)(17)(13)(1)(2)(1)(1)(1)(1)(1)(8)(1)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 如何更好地认识自己 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信