来源:Medium 本文将帮助您在使用 Java 代码时更好地理解Optional 的用途。 当我第一次开始使用 Java 代码时,经常有人建议我使用Optional。但当时我不太明白为什么使用Optional比实现空值处理更好。在这篇文章中,我想与大家分享为什么我认为我们都应该更多地使用Optional,以及如何避免过度可选化你的代码,这对代码质量是不利的。
什么是可选的?
Optional 参数用于携带对象并使空引用能够由各种 API 处理。我们看一下代码片段:Coffee coffee = new Coffee();
Integer quantity = coffee.getSugar().getQuantity();
我们有一个Coffee实例,其中我们从Sugar对象的实例中获取一些糖。如果我们假设从未在Coffee构造函数中设置数量值,则Coffee.getSugar().getQuantity()将返回NullPointerException。当然,我们总是可以使用旧的空检查来解决问题。
Coffee coffee = new Coffee();
Integer quantity = 0;
if (coffee.getSugar() != null) {
quantity = coffee.getSugar().getQuantity();
}
现在一切似乎都很好。但在编写Java代码时,我们最好避免实现空检查。让我们看看如何使用Optional 来完成此操作。
如何创建可选
创建Optional对象的方法有3种:-
of(T value) — 可选非空对象的实例化。请注意,使用of()引用null对象将引发NullPointerException。
-
ofNullable(T value) - 为可以为 null 的对象创建一个可选值。
-
empty() - 创建一个表示对null 的引用的可选实例。
// пример использования Optional.of(T Value)
String name = "foo";
Optional<String> stringExample = Optional.of(name)
// пример использования Optional.ofNullable(T Value)
Integer age = null;
Optional<Integer> integerExample= Optional.ofNullable(age)
// пример использования Optional.empty()
Optional<Object> emptyExample = Optional.empty();
所以你有一个可选对象。现在我们来看看Optional的两个主要方法:
-
isPresent() - 此方法告诉您Optional 对象是否包含非空值。
-
get() - 使用当前值检索可选值。请注意,对空的Optional调用get()将导致NullPointerException。
使用可选改进空检查
那么我们如何改进上面的代码呢?通过Optional,我们可以使用isPresent()了解对象的存在,并使用get()检索它。我们首先将coffee.getSugar()的结果与Optional 一起打包并使用isPresent()方法。这将帮助我们确定getSugar()是否返回null。Coffee coffee = new Coffee();
Optional<String> sugar = Optional.ofNullable(coffee.getSugar());
int quantity = 0;
if (sugar.isPresent()) {
Sugar sugar = sugar.get();
int quantity = sugar.getQuantity();
}
看这个例子,将coffee.getSugar() 的结果打包到Optional中似乎并没有增加任何价值,反而增加了麻烦。我们可以通过使用我认为是可选类中我最喜欢的函数来改进结果:
-
map(Function<? super T,? extends U> mapper) - 将Optional中包含的值映射到提供的函数。如果Optional参数为空,则map()将返回Optional.empty()。
-
orElse(T other)是get()方法的“特殊”版本。它可以获取Optional中包含的值。但是,如果是空Optional,这将返回传递给orElse()方法的值。
Coffee coffee = new Coffee();
Integer quantity = Optional.ofNullable(coffee.getSugar())
.map(it -> it.getQuantity())
.orElse(0);
这真的很酷——至少我这么认为。现在,如果在空值的情况下我们不想返回默认值,那么我们需要抛出某种异常。 orElseThrow(Supplier<? extends X> exceptionSupplier)返回Optional参数中包含的值,或者如果Optional为空则抛出异常。
Coffee coffee = new Coffee();
Integer quantity = Optional.ofNullable(coffee.getSugar())
.map(it -> it.getQuantity())
.orElseThrow(IllegalArgumentException::new);
正如您所看到的,Optional 提供了几个优点:
- 摘要空检查
- 提供用于处理null对象的 API
- 允许使用声明性方法来表达正在实现的目标
如何通过可选方式变得有效
在我的工作中,当方法可以返回“无结果”状态时,我使用Optional作为返回类型。我通常在定义方法的返回类型时使用它。Optional<Coffee> findByName(String name) {
...
}
有时这是没有必要的。例如,如果我有一个返回int 的方法,例如Sugar类中的getQuantity(),那么如果结果为null表示“无数量”,则该方法可能会返回0 。现在,知道了这一点,我们可以认为Coffee类中的Sugar参数可以表示为Optional。乍一看,这似乎是个好主意,因为从理论上讲,咖啡中不需要含有糖。然而,这就是我想解决什么时候不使用Optional的地方。 在以下场景中我们应该避免使用Optional:
-
作为方法参数。如果方法参数可以为null,那么从纯代码的角度来看,传递null仍然优于传递Optional。此外,您可以创建重载方法来抽象地处理缺少 null 方法参数的情况。
-
表示缺少的 Collection 对象。集合可以为空,因此空集合(如空集合或列表)必须用于表示没有值的集合。
GO TO FULL VERSION