Java 新增的Optional方法

Java 新增的Optional方法,用户希望执行以下操作:将 Optional 映射并展平到包含元素的流中;从几种可能的条件中进行选择;当元素存在时进行某种操作,否则返回默认值。使用 Java 9 为 Optional 类新增的 streamorifPresentOrElse 方法。

Java 新增的Optional方法 问题描述

用户希望执行以下操作:将 Optional 映射并展平到包含元素的流中;从几种可能的条件中进行选择;当元素存在时进行某种操作,否则返回默认值。

Java 新增的Optional方法 解决方案

使用 Java 9 为 Optional 类新增的 streamorifPresentOrElse 方法。

Java 新增的Optional方法 具体实例

Java 8 引入了 Optional 类,用于告知客户端返回值可能合法为 null。返回的并非 null,而是空 Optional。对可能返回(或不返回)值的方法而言,Optional 是一种不错的包装器。

1.stream方法
例 10-28 显示了一种根据 ID 检索客户的查找器方法(finder method)。

例 10-28 根据 ID 查找客户

public Optional<Customer> findById(int id) {
    return Optional.ofNullable(map.get(id));
}

findById 方法假设客户包含在内存的 Map 中。map.get 方法在键存在时返回一个值,否则返回 null,因此将其作为 Optional.ofNullable 方法的参数时,要么在 Optional 中包装一个非空值,要么返回一个空 Optional

由于 Optional.of 方法在参数为 null 时将抛出异常,采用 Optional.ofNullable(arg) 更方便,其实现为 arg != null ? Optional.of(arg) : Optional.empty()

findById 方法返回的是 Optional<Customer>,如果尝试返回客户集合则略显复杂。在 Java 8 中,不难写出如例 10-29 所示的代码。

例 10-29 在 Optional 上使用 filtermap 方法

public Collection<Customer> findAllById(Integer... ids) {
    return Arrays.stream(ids)
            .map(this::findById)           ➊
            .filter(Optional::isPresent)   ➋
            .map(Optional::get)            ➌
            .collect(Collectors.toList());
}

❶ 映射到 Stream<Optional<Customer>>
❷ 筛掉所有空 Optional
❸ 调用 get 方法以映射到 Stream<Customer>
上述实现并不难,但利用 Java 9 为 Optional 类新增的 stream 方法,可以使这个过程更简单。stream 方法的签名如下:

Stream<T> stream()

如果值存在,stream 方法将返回一个顺序的单元素流,流中仅包含该值;如果值不存在,stream 方法将返回一个空流。借由 stream 方法,可选的客户流可以直接转换为客户流,如例 10-30 所示。

例 10-30 使用传入 Optional.streamflatMap 方法

public Collection<Customer> findAllById(Integer... ids) {
    return Arrays.stream(ids)
            .map(this::findById)            ➊
            .flatMap(Optional::stream)      ➋
            .collect(Collectors.toList());
}

❶ 映射到 Stream<Optional<Customer>>
❷ 映射并展平为 Stream<Customer>
使用 stream 纯粹是为了方便,但它不失为一种有用的方法。

2.or 方法
orElse 方法用于从 Optional 中提取值,它传入默认值作为参数:

Customer customer = findById(id).orElse(Customer.DEFAULT)

也可以使用传入 Supplier 来创建默认值的 orElseGet 方法,不过这是一种成本较高的操作:

Customer customer = findById(id).orElseGet(() -> createDefaultCustomer())

orElseorElseGet 方法均返回 Customer 实例。而 Java 9 新增的 or 方法可以在给定 Supplier 时返回 Optional<Customer>,从而将查找客户的其他方式链接在一起。
or 方法的签名如下:

Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)

如果值存在,or 方法将返回描述该值的 Optional,否则返回由 Supplier 生成的 Optional
我们现在可以通过多种方式查找客户,例 10-31 展示了 or 方法的应用。

例 10-31 改用 or 方法

public Optional<Customer> findById(int id) {
    return findByIdLocal(id)
            .or(() -> findByIdRemote(id))
            .or(() -> Optional.of(Customer.DEFAULT));
}

程序首先在本地缓存中搜索客户,再访问远程服务器。如果两种方式都未能找到非空 Optional,最后一个子句创建一个默认值,将其包装在 Optional 中并返回。

3.ifPresentOrElse方法
如果 Optional 不为空,ifPresent 方法将执行 Consumer 指定的操作,如例 10-32 所示。

例 10-32 利用 ifPresent 方法仅打印非空客户

public void printCustomer(Integer id) {
    findByIdLocal(id).ifPresent(System.out::println);  ➊
}
 
public void printCustomers(Integer... ids) {
    Arrays.asList(ids)
            .forEach(this::printCustomer);
}

➊ 仅打印非空 Optional
虽然 ifPresent 方法很有用,不过如果返回的 Optional 为空,我们可能还希望执行其他操作。Java 9 新增的 ifPresentOrElse 方法包括两个参数,在 Optional 为空时将执行第二个参数 Runnable 指定的操作。该方法的签名如下:

void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)

使用 ifPresentOrElse 方法时,只需提供一个不传入任何参数并返回 void 的 lambda 表达式,如例 10-33 所示。

例 10-33 打印客户或默认消息

public void printCustomer(Integer id) {
    findByIdLocal(id).ifPresentOrElse(System.out::println,
            () -> System.out.println("Customer with id=" + id + " not found"));
}

如果找到指定的客户,程序将打印该客户,否则打印默认消息。
Optional 类新增的这些方法均未从根本上改变各自的用途,但它们确实为开发提供了更大的便利。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程