Skip to content

Optional

NullPointerException——Java 史上最常见的异常。

你一定见过这样的代码:

java
public String getCity(User user) {
    if (user != null) {
        if (user.getAddress() != null) {
            if (user.getAddress().getCity() != null) {
                return user.getAddress().getCity().getName();
            }
        }
    }
    return "未知";
}

嵌套 if,绕来绕去。Optional 让这件事变得优雅。

创建 Optional

三种创建方式

java
import java.util.Optional;

// 方式一:空值
Optional<String> empty = Optional.empty();

// 方式二:非空值(传入 null 会抛异常)
Optional<String> present = Optional.of("Hello");

// 方式三:可为 null(推荐大多数场景)
Optional<String> nullable = Optional.ofNullable(getName());
Optional<String> nullable2 = Optional.ofNullable(null);  // 返回空 Optional

什么时候用哪种

方法适用场景
Optional.empty()明确返回空值
Optional.of(value)确定值不为 null
Optional.ofNullable(value)不确定值是否可能为 null

判断与取值

判断值是否存在

java
Optional<String> opt = Optional.ofNullable(getName());

// JDK 8+
if (opt.isPresent()) {
    String value = opt.get();  // 安全取值
}

// JDK 11+:更语义化
if (opt.isEmpty()) {
    System.out.println("值为空");
}

获取值

java
Optional<String> opt = Optional.ofNullable(getName());

// get():直接取值,空值抛异常
String value = opt.get();

// orElse():空值时返回默认值
String value = opt.orElse("未知");

// orElseGet():空值时用 Supplier 计算
String value = opt.orElseGet(() -> {
    // 只在 opt 为空时才会执行
    return computeDefault();
});

// orElseThrow():空值时抛自定义异常
String value = opt.orElseThrow(() -> 
    new IllegalArgumentException("名称不能为空"));

orElse vs orElseGet

java
Optional<String> opt = Optional.empty();

// orElse:无论是否为空都执行
String a = opt.orElse(getDefault());  // ❌ getDefault() 总是被执行

// orElseGet:只在为空时执行
String b = opt.orElseGet(() -> getDefault());  // ✅ 只在 opt 为空时才执行

// 对比
private static String getDefault() {
    System.out.println("计算默认值");  // 这个方法会被调用吗?
    return "default";
}

链式操作

Optional 的真正威力在于链式调用。

map() — 转换

java
Optional<String> name = Optional.of("hello");

// 把 String 转成 Integer(长度)
Optional<Integer> length = name.map(String::length);
length.ifPresent(System.out::println);  // 5

// 嵌套属性安全获取
String city = Optional.ofNullable(user)
    .map(User::getAddress)
    .map(Address::getCity)
    .map(City::getName)
    .orElse("未知");

flatMap() — 避免嵌套 Optional

java
// map 的问题:返回值已经是 Optional 时
Optional<Optional<String>> nested = opt.map(this::findById);
// findById 返回 Optional<String>

// flatMap 解决:自动展开一层
Optional<String> result = opt.flatMap(this::findById);

filter() — 过滤

java
Optional<Integer> age = Optional.of(25);

// 保留满足条件的值
Optional<Integer> filtered = age.filter(a -> a > 18);
filtered.ifPresent(System.out::println);  // 25

// 不满足条件,返回空 Optional
Optional<Integer> filtered2 = age.filter(a -> a > 100);
filtered2.isEmpty();  // true

完整示例

替代嵌套 if

java
// ❌ 传统方式
public String getCityName(User user) {
    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            City city = address.getCity();
            if (city != null) {
                return city.getName();
            }
        }
    }
    return "未知";
}

// ✅ Optional 方式
public String getCityName(User user) {
    return Optional.ofNullable(user)
        .map(User::getAddress)
        .map(Address::getCity)
        .map(City::getName)
        .orElse("未知");
}

方法返回值

java
// ❌ 返回 null
public User findById(Long id) {
    return database.query(id);
}

// ✅ 返回 Optional
public Optional<User> findById(Long id) {
    return Optional.ofNullable(database.query(id));
}

// 调用方
user.findById(1L)
    .ifPresent(user -> System.out.println("找到: " + user.getName()));

集合操作

java
List<Optional<String>> list = Arrays.asList(
    Optional.of("a"),
    Optional.empty(),
    Optional.of("c")
);

// 过滤掉空值,收集非空值
List<String> result = list.stream()
    .flatMap(Optional::stream)
    .toList();
// [a, c]

// JDK 9+:直接用 Optional.ofNullable
List<String> nullableList = Arrays.asList("a", null, "c");
List<String> nonNull = nullableList.stream()
    .flatMap(s -> Optional.ofNullable(s).stream())
    .toList();

条件执行

java
Optional<String> config = getConfig();

// ❌ 传统方式
if (config.isPresent()) {
    process(config.get());
}

// ✅ ifPresent
config.ifPresent(this::process);

// ✅ ifPresentOrElse:处理两种情况
config.ifPresentOrElse(
    this::process,
    () -> System.out.println("配置为空")
);

注意事项

不要过度使用

java
// ❌ 过度使用:简单场景用 Optional 反而麻烦
String value = Optional.ofNullable(getValue())
    .map(Object::toString)
    .orElse(null);

// ✅ 简单场景直接判断
String value = getValue();
if (value != null) {
    // ...
}

不要用作字段类型

java
// ❌ Optional 不能序列化
public class User {
    private Optional<String> name;  // ❌ 不好
}

// ✅ 简单做法
public class User {
    private String name;
    
    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }
}

不要用作参数

java
// ❌ 不推荐
public void process(Optional<String> input) {
    input.ifPresent(this::doProcess);
}

// ✅ 推荐
public void process(String input) {
    String safeInput = Optional.ofNullable(input).orElse("");
    doProcess(safeInput);
}

小结

方法说明
Optional.empty()创建空 Optional
Optional.of(value)创建非空 Optional(null 会抛异常)
Optional.ofNullable(value)安全创建,可空
isPresent() / isEmpty()判断是否存在
get()获取值(空值抛异常)
orElse() / orElseGet() / orElseThrow()获取或默认值
ifPresent() / ifPresentOrElse()消费值
map() / flatMap()转换值
filter()过滤值

记住:Optional 是为了链式安全地处理 null,不是为了替代所有 null 判断。

基于 VitePress 构建