JavaRush /Java 博客 /Random-ZH /喝咖啡休息#161。如何使用Optional在Java中处理Null

喝咖啡休息#161。如何使用Optional在Java中处理Null

已在 Random-ZH 群组中发布
来源:Medium 本文将帮助您在使用 Java 代码时更好地理解Optional 的用途。 喝咖啡休息#161。 如何使用Optional在Java中处理Null - 1当我第一次开始使用 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时只使用get()isPresent() ,那么您就错过了!为了理解这一点,现在让我们用Optional重写上面的例子。

使用可选改进空检查

那么我们如何改进上面的代码呢?通过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()方法的值。

该方法将返回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:
  • 作为POJO(例如DTO)的参数类型。可选值不可序列化,因此在 POJO 中使用它们会使对象不可序列化。

  • 作为方法参数。如果方法参数可以为null,那么从纯代码的角度来看,传递null仍然优于传递Optional。此外,您可以创建重载方法来抽象地处理缺少 null 方法参数的情况。

  • 表示缺少的 Collection 对象。集合可以为空,因此空集合如空集合列表必须用于表示没有值的集合。

结论

Optional 已成为 Java 库的一个强大补充。它提供了一种处理可能不存在的对象的方法。因此,在制定方法时应予以考虑,不要陷入滥用的陷阱。是的,您可以编写出色的代码来实现 null 检查和 null 处理,但 Java 社区更喜欢使用Optional。它有效地传达了如何处理缺失值,比混乱的 Null 检查更容易阅读,并且从长远来看可以减少代码中的错误。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION