Java Optional介绍,创建,map 与 flatMap 的妙用

1. Optional 简介

为什么需要 Optional?

在 Java 8 之前,处理 null 是一个常见的痛点。代码中充斥着 if (obj != null) 的判断,不仅冗长,还容易遗漏,导致 NullPointerException
Optional 的设计目标

  • 明确表示“值可能不存在”的语义,替代隐式的 null
  • 强制开发者显式处理空值,减少 NPE 风险。
  • 支持链式函数式操作,提升代码可读性。

2. 创建 Optional 对象

Optional 提供三种核心创建方式:

2.1 Optional.of(T value)

  • 明确值非空时使用,若传入 null 会抛出 NullPointerException
String name = "Java";
Optional<String> opt = Optional.of(name);  // 安全

2.2 Optional.ofNullable(T value)

  • 允许值为空,若传入 null,返回 Optional.empty()
String name = getFromExternal(); // 可能返回 null
Optional<String> opt = Optional.ofNullable(name); // 安全

2.3 Optional.empty()

  • 显式表示空值,等价于 Optional.ofNullable(null)
Optional<String> emptyOpt = Optional.empty();

3. 使用 map 提取和转换对象

map 方法用于对 Optional 中的值进行转换,返回新的 Optional。

3.1 基本用法

  • 如果 Optional 有值,则应用函数转换;若为空,返回 Optional.empty()
Optional<String> upperName = Optional.of("java")
    .map(String::toUpperCase); // 转换为 "JAVA"

3.2 避免嵌套 Optional

  • 错误示例:函数返回 Optional 时,直接使用 map 会导致嵌套的 Optional>
Optional<Optional<String>> badResult = Optional.of("[email protected]")
    .map(email -> findUserByEmail(email)); // findUserByEmail 返回 Optional

4. 使用 flatMap 链接 Optional 对象

flatMap 解决嵌套 Optional 的问题,实现链式扁平化操作

4.1 核心作用

  • 如果映射函数返回 Optional,使用 flatMap 会自动“解包”为 Optional,避免嵌套。
Optional<User> user = Optional.of("[email protected]")
    .flatMap(email -> findUserByEmail(email)); // 返回 Optional

4.2 对比 map 和 flatMap

方法 输入 映射函数返回值 结果
map Optional R Optional
flatMap Optional Optional Optional

4.3 链式调用示例

Optional<String> city = Optional.of("[email protected]")
    .flatMap(email -> findUserByEmail(email))  // Optional
    .flatMap(user -> findAddressByUser(user))  // Optional
.map(address -> address.getCity()); // Optional

5. 实战案例:链式处理用户数据

假设需要从邮箱查找用户,再获取用户的地址城市:

5.1 定义类结构

class User {
    private String email;
    private Optional<Address> address;
    // getters
}

class Address {
    private String city;
    // getter
}

5.2 链式查询

Optional<String> city = Optional.of("[email protected]")
    .flatMap(email -> userRepository.findByEmail(email)) // Optional
    .flatMap(User::getAddress)  // Optional
(注意:User::getAddress 返回 Optional) .map(Address::getCity); // Optional

5.3 处理结果

String result = city.orElse("Unknown City");

6. 注意事项

  1. 不要滥用 Optional
    • 避免将 Optional 用作方法参数或类的字段,因为他并未实现Serializable接口。如果一定要实现序列化的域模型,作为替代方案,如下:
    public class Person {
     private String Car;
     public Optional getCarAsOptional() {
         return Optional.ofNullable(car);
     }
    

}

   - 不要用 Optional 替代集合(如 `List` 的空判断)。

2. **优先使用 orElse/orElseGet**  
   - `orElse(T)`:无论 Optional 是否为空都会计算默认值。
   - `orElseGet(Supplier)`:仅在 Optional 为空时计算默认值,性能更优。

3. **慎用 get()**  
   - 直接调用 `get()` 可能导致 `NoSuchElementException`,建议使用 `orElse` 或 `ifPresent`。

---

## **7. 总结**

- **Optional 的核心价值**:通过显式空值处理,减少 NPE 风险,提升代码可读性。
- **map vs. flatMap**:
  - `map`:转换值,返回 `Optional`。
  - `flatMap`:转换值并解包嵌套 Optional,返回 `Optional`。
- **链式调用**:结合 `flatMap` 和 `map`,可以优雅处理多层 Optional 依赖关系。


你可能感兴趣的:(java,Optional,flatMap)