Java Optional.flatMap与Optional.map方法

Java Optional.flatMap与Optional.map方法,用户希望避免将一个 Optional 包装在另一个 Optional 中,使用 Optional 类定义的 flatMap 方法,有关 Stream 接口定义的 mapflatMap 方法请参见范例使用flatMap与map方法

Java Optional.flatMap与Optional.map方法 问题描述

用户希望避免将一个 Optional 包装在另一个 Optional 中。

Java Optional.flatMap与Optional.map方法 解决方案

使用 Optional 类定义的 flatMap 方法。

Java Optional.flatMap与Optional.map方法 具体实例

有关 Stream 接口定义的 mapflatMap 方法请参见范例使用flatMap与map方法。不过 flatMap 是一个通用的概念,同样可以用于 Optional
Optional.flatMap 方法的签名如下:

<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

Optional.flatMap 方法的签名与 Optional.map 方法类似,二者的 Function 参数应用于每个元素并生成一个结果,返回类型为 Optional<U>。具体而言,如果参数 T 存在,Optional.flatMap 方法将函数应用于 T 并返回 Optional,它包装包含的值;如果 T 不存在,方法将返回一个空 Optional
根据范例getter和setter方法中的Optional的讨论,数据访问对象(DAO)通常采用返回 Optional 的 getter 方法编写(如果属性可以为 null),但 setter 方法不会将参数包装在 Optional 中。例 6-13 显示了两个类,一个是 Manager 类,它包含非空字符串 name;另一个是 Department 类,它包含可空 Manager 特性 boss

例 6-13 包含 Optional 的 DAO 层(部分)

public class Manager {
    private String name;                  ➊

    public Manager(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

public class Department {
    private Manager boss;                 ➋

    public Optional<Manager> getBoss() {
        return Optional.ofNullable(boss);
    }

    public void setBoss(Manager boss) {
        this.boss = boss;
    }
}

❶ 假定不为 null,因此不需要 Optional
❷ 可能为 null,因此在 Optional 中包装 getter 方法并返回,但不要对 setter 方法执行同样的操作
如果客户端调用 DepartmentgetBoss 方法,结果将被包装在 Optional 中,如例 6-14 所示。

例 6-14 返回 Optional

Manager mrSlate = new Manager("Mr. Slate");

Department d = new Department();
d.setBoss(mrSlate);                          ➊
System.out.println("Boss: " + d.getBoss());  ➋

Department d1 = new Department();            ➌
System.out.println("Boss: " + d1.getBoss()); ➍

Department 中存在非空 Manager
❷ 打印 Boss: Optional[Manager{name='Mr. Slate'}]
Department 中不存在 Manager
❹ 打印 Boss: Optional.empty
截至目前一切顺利。如果 Department 中存在 Manager,getter 方法将其包装在 Optional 中并返回;如果 Department 中不存在 Manager,getter 方法将返回一个空 Optional
问题在于,无法通过在 Optional 上调用 getName 方法来获取 Managername。我们要么从 Optional 中取出包含的值,要么使用 map 方法(例 6-15)。

例 6-15 从 OptionalManager 中提取 name

System.out.println("Name: " +
        d.getBoss().orElse(new Manager("Unknown")).getName());   ➊

System.out.println("Name: " +
        d1.getBoss().orElse(new Manager("Unknown")).getName());

System.out.println("Name: " + d.getBoss().map(Manager::getName));  ➋
System.out.println("Name: " + d1.getBoss().map(Manager::getName));

❶ 在调用 getName 方法之前从 Optional 中提取 boss
❷ 利用 map 方法将 getName 应用于包含的 Manager
仅当 map 方法所调用的 Optional 不为空时,该方法才会应用给定函数,因此这种方案更为简单。map 方法的详细讨论请参见范例Optional的映射
不过,如果多个 Optional 链接在一起,情况将变得较为复杂。例 6-16 定义了一个名为 Company 的类,它只包含一个 Department(为简单起见,只考虑一个 Department 的情况)。

例 6-16 只包含一个 DepartmentCompany

public class Company {
    private Department department;

    public Optional<Department> getDepartment() {
        return Optional.ofNullable(department);
    }

    public void setDepartment(Department department) {
        this.department = department;
    }
}

如果在 Company 类上调用 getDepartment 方法,结果将被包装在 Optional 中。为获取 Manager 的信息,似乎可以采用例 6-15 讨论的 map 方法,但这会导致一个 Optional 被包装在另一个 Optional 中,如例 6-17 所示。

例 6-17 包装在另一个 Optional 中的 Optional

Company co = new Company();
co.setDepartment(d);

System.out.println("Company Dept: " + co.getDepartment());        ➊

System.out.println("Company Dept Manager: " + co.getDepartment()
    .map(Department::getBoss));                                   ➋

❶ 打印 Company Dept: Optional[Department{boss=Manager{name='Mr.Slate'}}]
❷ 打印 Company Dept Manager: Optional[Optional[Manager{name='Mr.Slate'}]]
为解决这个问题,不妨使用 Optional.flatMap 方法。flatMap 方法可以将结构“展平”,因此只会返回一个 Optional。我们仍然按之前的方式创建 Company 类,然后应用 flatMap 方法,如例 6-18 所示。

例 6-18 在 Company 上应用 flatMap

System.out.println(
    co.getDepartment()                ➊
        .flatMap(Department::getBoss) ➋
        .map(Manager::getName));      ➌

Optional<Department>
Optional<Manager>
Optional<String>
接下来,将 Company 也包装在 Optional 中,如例 6-19 所示。

例 6-19 在 OptionalCompany 上应用 flatMap

Optional<Company> company = Optional.of(co);

System.out.println(
    company                               ➊
        .flatMap(Company::getDepartment)  ➋
        .flatMap(Department::getBoss)     ➌
        .map(Manager::getName)            ➍
);

Optional<Company>
Optional<Department>
Optional<Manager>
Optional<String>
不难看到,我们甚至可以将 Company 包装在 Optional 中,然后重复执行 flatMap 操作就能获取任何所需的属性,最后通过 map 操作结束。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程