Java Optional 类完整教程

一、什么是 Optional?

Optional 是 Java 8 引入的一个容器类,用于包装可能为 null 的对象。
它的核心作用是优雅地处理空值,避免直接操作 null 导致的 NullPointerException,同时让代码意图更清晰。

二、开发思路
  1. 理解传统 null 处理的问题(嵌套判断繁琐、易抛空指针)
  2. 掌握 Optional 的创建方式(3 种核心方法)
  3. 学习 Optional 的常用 API(判断、取值、转换、过滤等)
  4. 掌握链式调用技巧(简化多层 null 检查)
  5. 规避常见错误(过度使用 isPresent()、错误使用 of() 等)
三、代码示例与逐行注释
1. 准备测试类

先定义一个简单的实体类,用于后续示例:

// 用户类
class User {
  private String name;  // 用户名
  private Address address;  // 地址(可能为null)

  // 构造方法
  public User(String name, Address address) {
    this.name = name;
    this.address = address;
  }

  // getter方法
  public String getName() { return name; }
  public Address getAddress() { return address; }
}

// 地址类
class Address {
  private String city;  // 城市(可能为null)

  public Address(String city) {
    this.city = city;
  }

  public String getCity() { return city; }
}
2. Optional 的创建方式

Optional 提供 3 种创建实例的方法,适用于不同场景:

import java.util.Optional;

public class OptionalDemo {
  public static void main(String[] args) {
    // 1. 创建空的Optional(值为null)
    Optional<String> emptyOpt = Optional.empty();
    // 注意:empty()返回的是一个单例空实例,而非直接new Optional()

    // 2. 创建包含非null值的Optional(值绝对不为null时用)
    String str = "hello";
    Optional<String> nonNullOpt = Optional.of(str);
    // 若str为null,of()会直接抛NullPointerException
    // Optional<String> nullOpt = Optional.of(null);  // 运行时异常

    // 3. 创建可能为null值的Optional(值可能为null时用)
    String nullableStr = null;
    Optional<String> nullableOpt = Optional.ofNullable(nullableStr);
    // ofNullable()会自动处理null:若值为null,返回空Optional
  }
}
3. 常用 API 详解
(1)判断值是否存在:isPresent() / isEmpty()
public class OptionalApi1 {
  public static void main(String[] args) {
    Optional<String> opt1 = Optional.of("test");
    Optional<String> opt2 = Optional.empty();

    // 判断值是否存在(非空)
    boolean hasValue1 = opt1.isPresent();  // true
    boolean hasValue2 = opt2.isPresent();  // false

    // Java 11+:判断值是否不存在(为空)
    boolean isEmpty1 = opt1.isEmpty();  // false
    boolean isEmpty2 = opt2.isEmpty();  // true
  }
}
(2)值存在时执行操作:ifPresent()
public class OptionalApi2 {
  public static void main(String[] args) {
    Optional<String> opt = Optional.of("hello");

    // 若值存在,执行Lambda表达式(参数为非null值)
    opt.ifPresent(s -> System.out.println(s.length()));  // 输出:5

    // 若值不存在,不执行任何操作
    Optional.empty().ifPresent(s -> System.out.println(s));  // 无输出

    // Java 9+:ifPresentOrElse(存在时执行操作,不存在时执行另一个操作)
    opt.ifPresentOrElse(
      s -> System.out.println("值为:" + s),  // 存在时执行
      () -> System.out.println("值不存在")    // 不存在时执行
    );  // 输出:值为:hello
  }
}
(3)获取值:get() / orElse() / orElseGet() / orElseThrow()
public class OptionalApi3 {
  public static void main(String[] args) {
    Optional<String> opt1 = Optional.of("java");
    Optional<String> opt2 = Optional.empty();

    // 1. get():获取值(仅在确定值存在时使用!)
    String val1 = opt1.get();  // "java"
    // String val2 = opt2.get();  // 抛NoSuchElementException

    // 2. orElse():值不存在时返回默认值(默认值始终会被创建)
    String val3 = opt1.orElse("default");  // "java"(用opt1的值)
    String val4 = opt2.orElse("default");  // "default"(用默认值)

    // 3. orElseGet():值不存在时通过Supplier生成默认值(默认值按需创建)
    // 适合默认值创建成本高的场景(如数据库查询)
    String val5 = opt1.orElseGet(() -> "生成的默认值");  // "java"
    String val6 = opt2.orElseGet(() -> "生成的默认值");  // "生成的默认值"

    // 4. orElseThrow():值不存在时抛指定异常
    String val7 = opt1.orElseThrow(() -> new RuntimeException("值为空"));  // "java"
    try {
      String val8 = opt2.orElseThrow(() -> new RuntimeException("值为空"));
    } catch (RuntimeException e) {
      System.out.println(e.getMessage());  // 输出:值为空
    }
  }
}
(4)转换值:map() / flatMap()

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

public class OptionalApi4 {
  public static void main(String[] args) {
    // 1. map():将值转换为另一种类型(自动包装为Optional)
    Optional<String> strOpt = Optional.of("hello");
    // 将字符串转换为它的长度(int)
    Optional<Integer> lengthOpt = strOpt.map(s -> s.length());
    lengthOpt.ifPresent(len -> System.out.println(len));  // 输出:5

    // 2. flatMap():转换后的值本身就是Optional(用于嵌套Optional场景)
    User user = new User("张三", new Address("北京"));
    Optional<User> userOpt = Optional.of(user);

    // 需求:获取用户地址的城市(Address可能为null,city可能为null)
    // 用map()会得到Optional<Optional<String>>(不推荐)
    Optional<Optional<String>> cityOpt1 = userOpt
      .map(u -> Optional.ofNullable(u.getAddress()))  // 先获取Address的Optional
      .map(addrOpt -> addrOpt.map(Address::getCity));  // 再获取city的Optional

    // 用flatMap()直接得到Optional<String>(推荐)
    Optional<String> cityOpt2 = userOpt
      .flatMap(u -> Optional.ofNullable(u.getAddress()))  // 展开为Address的Optional
      .flatMap(addr -> Optional.ofNullable(addr.getCity()));  // 展开为city的Optional

    cityOpt2.ifPresent(city -> System.out.println(city));  // 输出:北京
  }
}
(5)过滤值:filter()

用于按条件过滤 Optional 中的值,符合条件保留,否则返回空 Optional。

public class OptionalApi5 {
  public static void main(String[] args) {
    Optional<Integer> numOpt = Optional.of(10);

    // 过滤:只保留大于5的数字
    Optional<Integer> filteredOpt1 = numOpt.filter(n -> n > 5);
    filteredOpt1.ifPresent(n -> System.out.println(n));  // 输出:10

    // 过滤:保留小于5的数字(不符合,返回空)
    Optional<Integer> filteredOpt2 = numOpt.filter(n -> n < 5);
    System.out.println(filteredOpt2.isEmpty());  // 输出:true
  }
}
4. 实际开发案例:多层 null 检查简化

传统方式处理多层对象的 null 检查会很繁琐,用 Optional 链式调用可简化:

public class OptionalPractice {
  public static void main(String[] args) {
    // 场景:获取用户的城市,若任何一环为null,返回"未知城市"
    User user1 = new User("李四", new Address("上海"));  // 完整数据
    User user2 = new User("王五", null);  // 地址为null
    User user3 = null;  // 用户为null

    // 传统方式(嵌套if,繁琐)
    String city1 = getCityTraditional(user1);
    System.out.println(city1);  // 上海

    // Optional方式(链式调用,简洁)
    String city2 = getCityWithOptional(user2);
    System.out.println(city2);  // 未知城市

    String city3 = getCityWithOptional(user3);
    System.out.println(city3);  // 未知城市
  }

  // 传统方式获取城市
  private static String getCityTraditional(User user) {
    if (user != null) {
      Address address = user.getAddress();
      if (address != null) {
        String city = address.getCity();
        if (city != null) {
          return city;
        }
      }
    }
    return "未知城市";
  }

  // Optional方式获取城市
  private static String getCityWithOptional(User user) {
    return Optional.ofNullable(user)  // 包装user(可能为null)
      .flatMap(u -> Optional.ofNullable(u.getAddress()))  // 转换为Address的Optional
      .flatMap(addr -> Optional.ofNullable(addr.getCity()))  // 转换为city的Optional
      .orElse("未知城市");  // 任何一环为null则返回默认值
  }
}
四、最佳实践与注意事项
  1. 用 Optional 作为返回值,而非参数:方法参数用 Optional 会增加调用方复杂度,不推荐。
  2. 避免过度使用 isPresent() + get():这等价于传统的 if (obj != null),失去了 Optional 的优势,应优先用 ifPresent()、orElse() 等。
  3. of() 和 ofNullable() 选择:确定值非 null 用 of(),可能为 null 用 ofNullable()。
  4. 链式调用优先:通过 map()、flatMap()、filter() 链式处理,简化代码。
  5. 不要嵌套 Optional:如 Optional<Optional<String>>,应通过 flatMap() 展开。
五、总结

Optional 是处理 null 的优雅方案,核心价值在于明确表达“值可能不存在”的语义,并通过链式 API 简化空值处理逻辑。合理使用可大幅减少 NullPointerException,提升代码可读性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐