1. 引言

Java 8引入了Optional类来表示可能存在也可能不存在的值。它帮助我们避免NullPointerException,并编写更具表现力和可读性的代码。 在需要将可选值作为列表处理的场景中,将Optional转换为ArrayList会很有用。本文将探讨在Java中将Optional转换为ArrayList的几种方法。

2. 使用ifPresent()

这种方法利用Optional类提供的ifPresent()方法来处理值的存在或缺失。它允许我们仅在Optional包含值时执行代码块,无需显式进行null检查,提高了代码可读性。

看一个使用ifPresent()方法的代码片段:

Optional<String> optionalValue = Optional.of("Hello, World!");

List<String> arrayList = new ArrayList<>();
optionalValue.ifPresent(arrayList::add);

assertTrue(arrayList.contains("Hello, World!"));

我们首先创建一个名为optionalValueOptional对象,包含值"Hello, World!"。这个值被封装在Optional中,表示它可能不存在。 接着,我们在optionalValue上调用ifPresent()方法。**ifPresent()方法接受一个lambda表达式或方法引用作为参数,并在Optional包含值时执行它。**

本例中,方法引用arrayList::add会在值存在时将其添加到ArrayList中。

3. 使用orElse()orElseGet()

这种方法利用Optional类提供的orElse()方法。它允许我们指定一个默认值,在Optional为空时使用。当我们有备用值或行为需要在Optional不包含值时应用时,这特别有用。

在这个例子中,我们创建一个空的Optional,所以调用orElse()方法时会返回默认值"Hello World":

Optional<String> emptyOptional = Optional.empty();

List<String> arrayList = new ArrayList<>();
arrayList.add(emptyOptional.orElse("Hello World!"));

assertTrue(arrayList.contains("Hello, World!"));

示例中,我们使用empty()方法创建了一个名为emptyOptional的空Optional。由于emptyOptional为空,调用orElse()将返回指定的默认值"Hello World"。然后我们将这个默认值添加到ArrayList中。

⚠️ 注意:使用orElse()时,提供的默认值会被立即求值这意味着无论Optional是否需要它,都会计算默认值。 即使Optional包含非空值,默认值仍会被创建,orElseGet()提供的默认值是延迟求值的。它仅在Optional为空时才会被调用。

此外,在性能敏感的场景中,通常更推荐使用orElseGet(),因为它避免了在Optional已包含值时不必要的计算:

Optional<String> emptyOptional = Optional.empty(); 

List<String> arrayList = new ArrayList<>(); 
arrayList.add(emptyOptional.orElseGet(() -> "Hello, World!")); 

assertTrue(arrayList.contains("Hello, World!"));

4. 使用Java Streams

Java中的Stream表示一个元素序列,可以在操作管道中处理。我们可以利用Streams API来有条件地创建ArrayList

4.1. 基本实现

看一个使用Java Streams将Optional对象转换为ArrayList的例子:

Optional<String> optionalValue = Optional.of("Hello, World!");

List<String> arrayList = optionalValue
  .stream()
  .collect(Collectors.toList());

assertTrue(arrayList.contains("Hello, World!"));

首先,我们创建一个名为optionalValueOptional对象,值为"Hello, World!"。接着,我们使用Java Stream将Optional转换为ArrayList我们在optionalValue上调用stream()方法获取其元素的流。 然后使用collect()方法和Collectors.toList()将流中的元素收集到一个List中,从而将Optional转换为ArrayList

如果Optional为空(即不包含值),结果ArrayList也将为空。在Java Streams中,如果流源为空,终端操作(本例中的collect())将直接返回一个空集合。

4.2. 流过滤

使用Java Stream API的一个优势是它允许我们有条件地处理元素并执行各种转换。 假设我们只想将满足特定条件的值添加到ArrayList中。Streams允许我们在将元素收集到列表之前加入filter()操作:

Optional<String> optionalValue = Optional.of("Hello, World!");

List<String> arrayList = optionalValue
  .filter(e -> e.startsWith("H"))
  .stream()
  .collect(Collectors.toList());

assertTrue(arrayList.contains("Hello, World!"));

这里,我们使用filter()过滤包含StringOptional。该方法只保留以字母"H"开头的元素。然后使用collect(Collectors.toList())方法将过滤后的元素收集到ArrayList中。

4.3. 流扁平化

Java Streams在处理嵌套列表时提供了额外优势。 考虑一个场景:一个Optional包含另一个Optional,后者又持有一个列表。我们可以使用Java Streams来扁平化这个嵌套列表。

写一个示例演示如何扁平化Optional中的嵌套列表:

Optional<List<String>> optionalList = Optional.of(Arrays.asList("Apple", "Banana", "Cherry"));

List<String> arrayList = optionalList
  .stream()
  .flatMap(List::stream)
  .collect(Collectors.toList());

assertEquals(3, arrayList.size());
assertTrue(arrayList.contains("Apple"));

我们在Optional<List<String>>上调用stream()将其转换为流。接着使用flatMap(List::stream)。这会对流中的每个元素应用List::stream方法引用。通过应用flatMap(),我们实质上"扁平化"了嵌套结构。 现在我们得到的是一个包含内部列表中各个元素的流,而不是包含单个列表的流。

5. 总结

本文探讨了将Optional转换为ArrayList的几种方法:

✅ 当需要根据Optional值的存在执行特定操作时,使用ifPresent()方法
✅ 当Optional为空时有默认值可用时,使用orElse()orElseGet()
Java Streams是简洁转换的好选择,特别是在转换为列表前需要过滤时

所有示例代码的源码可在GitHub上获取。


原始标题:Convert an Optional to an ArrayList in Java | Baeldung