JDK1.8 新特性 (八):还在重复写空指针检查代码?赶紧使用 Optional 吧!
点击上方“程序猿技术大咖”,关注加群讨论
1、前言
是的,你没有看错,NullPointerException位居榜首。
Null Reference的发明者Charles Antony Richard Hoare说过:
“我称之为我的十亿美元错误。这是1965年发明空引用的结果……这导致了无数的错误,漏洞和系统崩溃,在最近40年中可能造成十亿美元的痛苦和破坏。”
NullPointerException
简直就是程序员心中的痛,并不是说它有多难以解决,而是为了解决它我们需要再付出了额外代价。
NullPointerException
而引发的bug,解决完一个,又在另一个地方遇到。这也慢慢让你懂得,不要相信任何“对象”,特别是别人提供给你的,在使用的地方都加上判断,这样就放心多了。于是代码通常就变成了下面这样:
String name = "Unknown";if (null != people) {if (null != people.getName()) {name = people.getName();}}return name;
NullPointerException
了,但是过多的判断语句着实让人头皮发麻,代码变得臃肿不堪。如果对象过于复杂,对象里面还有对象等等,你还要继续逐层判断么?
java.util.Optional<T>
,凭借Optional类提供的API,我们再也不用担心
NullPointerException
了,更不会再去写那些烦人的判断啦。
2、Optional类
Optional
类只是对类简单封装。变量不存在时,缺失的值会被建模成一个“空”的
Optional
对象,由方法
Optional.empty()
返回。
Optional.empty()
方法是一个静态工厂方法,它返回Optional类的特定单一实例。
Optional
,本质上是一个容器对象,拥有一个非空值或空值,需要我们将对象实例传入该容器中。如果值存在,
Optional.isPresent()
方法返回
true
,并通过
Optional.get()
方法获取值。
Optional
的构造方法为
private
,无法直接使用new来创建
Optional
对象,只能使用
Optional
提供的静态方法创建。
-
Optional.of(obj):如果对象为 null,将会抛出NullPointerException。 -
Optional.ofNullable(obj):如果对象为 null,将会创建不包含值的 EMPTY Option al对象实例(new Optional<>())。 -
Optional.empty():等同于 Optional.ofNullable(null)。
/*** Constructs an instance with the value present.** @param value the non-null value to be present* @throws NullPointerException if value is null*/private Optional(T value) {this.value = Objects.requireNonNull(value);}……/*** Returns an {@code Optional} with the specified present non-null value.** @param <T> the class of the value* @param value the value to be present, which must be non-null* @return an {@code Optional} with the value present* @throws NullPointerException if value is null*/public static <T> Optional<T> of(T value) {return new Optional<>(value);}
/*** Returns an {@code Optional} describing the specified value, if non-null,* otherwise returns an empty {@code Optional}.** @param <T> the class of the value* @param value the possibly-null value to describe* @return an {@code Optional} with a present value if the specified value* is non-null, otherwise an empty {@code Optional}*/public static <T> Optional<T> ofNullable(T value) {return value == null ? empty() : of(value);}
/*** Common instance for {@code empty()}.*/private static final Optional> EMPTY = new Optional<>();……/*** Returns an empty {@code Optional} instance. No value is present for this* Optional.** @apiNote Though it may be tempting to do so, avoid testing if an object* is empty by comparing with {@code ==} against instances returned by* {@code Option.empty()}. There is no guarantee that it is a singleton.* Instead, use {@link #isPresent()}.** @param <T> Type of the non-existent value* @return an empty {@code Optional}*/public static<T> Optional<T> empty() {@SuppressWarnings("unchecked")Optional<T> t = (Optional<T>) EMPTY;return t;}
Optional.ofNullable(obj)
方法,来创建
Optional
对象,并获取对应值。
3、Optional的使用
Optional
的好处了吧,但是,我们该如何使用呢?
Optional
对象,即:使用静态工程方法
Optional.ofNullable(obj)
,创建一个可以允许null值的
Optional
对象:
Optional<People> optional = Optional.ofNullable(people);
即使people是null,optional对象也就是个空对象。
如果people不为null,根据Optional.isPresent()方法返回true,并通过Optional.get()方法获取值。
为了避免NPE, Optional.isPresent()方法已经对null进行了判断,若存在返回true。
People p = null;if (optional.isPresent()) { p = optional.get();}
看到这里,你可能会发现这与null判断检查并无差异。
后来接触到Optional其他API,我才发现真正体现它价值的是下面这些API。
3.1 Optional.map
String name = null;if (null != people) {name = people.getName();}
使用Optional.map方法,可以这么写:
Optional<People> optional = Optional.ofNullable(people);Optional<String> stringOptional = optional.map(People::getName);
3.2 Optional.orElse
当一个对象为 null 时,业务上通常可以设置一个默认值,从而使流程继续下去。
String name = null != people ? people.getName() : "Unknown";
或者抛出一个异常。
if (null != people.getName()) {throw new RuntimeException();}
Optional 类提供两个方法 orElse 与 orElseThrow ,可以方便完成上面转化。
// 设置默认值String name = optional.orElse(new People("Unknown")).getName();// 抛出异常String name = optional.orElseThrow(RuntimeException::new).getName();
如果 optional 为空,提供默认值或抛出异常。
3.3 Optional.filter
if (null != people && "xcbeyond".equals(people.getName())) { System.out.println("ok");}
使用Optional类提供的方法filter,可以很好的重构:
optional.filter(people1 -> "xcbeyond".equals(people.getName())) .ifPresent(x -> System.out.print("ok"));
4、Optional重构代码
让我们一起再看看文章开头的代码:
String name = "Unknown";if (null != people) { if (null != people.getName()) { name = people.getName(); }}return name;
在知道了Optional之后,进行代码重构:
Optional<People> optional = Optional.ofNullable(people);return optional.map(People::getName).orElse("Unknown");
参考文章:
1.https://dzone.com/articles/the-top-10-exception-types-in-production-java-appl
2.《Java 8实战》
喜欢就点个"在看"呗,留言、转发朋友圈
本文分享自微信公众号 - 程序猿技术大咖(cxyjsdk)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。



