1. 概述
多年来,空引用(null references)和值一直在困扰着程序员。null引用的发明者Tony Hoare甚至称其为“十亿美元的错误”。特别是Java,一直在与null值及其令人畏惧的NullPointerException
进行斗争。
Java 8引入了Optional
类来应对这个挑战,确保妥善处理null和空结果。在这篇教程中,我们将探讨如何在所有Optional
变量都包含值时执行操作,否则忽略该操作。
2. 假设
本教程演示了使用三个Optional
变量,但概念可以轻松扩展以处理更多。此外,让我们声明这些变量,这些将在本文中使用:
var name = Optional.of("Jean-Luc Picard");
var designation = Optional.of("Captain");
var ship = Optional.of("USS Enterprise D");
在这个例子中,为了简洁,我们定义了Optional<String>
。然而,文章中讨论的原则同样适用于其他引用类型。
3. 使用isPresent()
Optional
提供了一个有用的isPresent()
方法,用于检查其中是否包含值。如果存在值,此方法返回true,如果Optional
为空,则返回false。让我们看看实现:
var action = false;
if (name.isPresent() && designation.isPresent() && ship.isPresent()) {
action = true;
}
Assertions.assertTrue(action);
在这个示例中,我们使用Optional.of()
创建Optional
实例。然后,我们在每个实例上使用isPresent()
,并在所有值都存在时才执行操作。虽然这种方法明显简单且易于阅读,但在处理多个变量时会变得繁琐。
4. 使用flatMap()
和map()
Java 8将函数式编程概念引入了语言。通过flatMap()
和map()
等方法,我们现在可以在容器类型(如Optional
)中的值上执行操作。利用flatMap()
和map()
,我们可以有效地只在所有值都存在时检查并执行操作。
让我们看看使用这种方法的实现:
var action = name.flatMap(n -> designation.flatMap(d -> ship.map(s -> true)));
Assertions.assertEquals(action, Optional.of(true));
在上述示例中,我们使用flatMap()
和map()
链接多个Optional
实例。这些函数设计为短路操作;如果链中的任何步骤没有值,操作立即终止,并返回一个空的结果。
我们可以通过引入另一个测试用例来验证这种行为:
var name = Optional.of("Jean-Luc Picard");
var designation = Optional.of("Captain");
var ship = Optional.empty();
var action = name.flatMap(n -> designation.flatMap(d -> ship.map(s -> true)));
Assertions.assertTrue(action.isEmpty());
在这里,我们可以看到action
变量是空的,因为船只没有值。
虽然这种方法强大,但当需要连接众多值时,它往往会变得更加冗长。
5. 使用ifPresent()
另一种选择是,如果我们不需要返回值,只需要在所有值都存在时执行操作,我们可以使用ifPresent()
配合lambda表达式。让我们看看示例代码:
name.ifPresent(n -> designation.ifPresent(d -> ship.ifPresent(s -> System.out.println("Perform action instead!"))));
在这种情况下,我们使用ifPresent()
链接每个Optional
实例,并仅在所有值都存在时执行操作。
6. 使用Stream.of()
Java流提供了另一种确保只有在所有值都存在时才执行操作的方法。我们可以使用Stream.of()
创建一个Optional
值的流,并使用allMatch()
方法检查流中的每个元素是否包含值。
让我们看看实现:
var status = false;
var allPresent = Stream.of(name, designation, ship).allMatch(Optional::isPresent);
if (allPresent) {
// Perform action if all values present
status = true;
}
Assertions.assertTrue(status);
在这个示例中,我们使用allMatch()
和Optional.isPresent()
一起验证流中的所有元素都存在。
这提供了一种简洁的方式来执行所需的验证。与其他方法不同,添加更多的Optional
值并不会降低可读性。这使得流成为处理越来越多Optional
值的高可扩展解决方案。
7. 总结
在这篇教程中,我们探讨了在所有Optional
值都可用时执行操作的不同方法。我们首先检查了简单的if...else
条件,然后探索了利用函数式编程概念和流API的替代技术。最终,最合适的实现方式取决于具体情境的需求。
如往常一样,本文使用的示例代码可在GitHub上找到。