知识模块
☕ Java 知识模块
六、Java 新特性
Optional 类

Optional 类

面试提问

"Optional 类的作用是什么?如何正确使用?"


Optional 简介

Optional 是 Java 8 引入的容器类,用于优雅地处理空值,避免 NullPointerException

创建 Optional

// 创建空 Optional
Optional<String> empty = Optional.empty();
 
// 创建非空 Optional(value 为 null 会抛异常)
Optional<String> opt1 = Optional.of("Hello");
 
// 创建 Optional(value 可以为 null)
Optional<String> opt2 = Optional.ofNullable("Hello");
Optional<String> opt3 = Optional.ofNullable(null);  // 等同于 empty()

常用方法

获取值

Optional<String> opt = Optional.of("Hello");
 
// get():有值返回,无值抛 NoSuchElementException
String s1 = opt.get();
 
// orElse():有值返回,无值返回默认值
String s2 = opt.orElse("Default");
 
// orElseGet():有值返回,无值调用 Supplier
String s3 = opt.orElseGet(() -> "Default");
 
// orElseThrow():有值返回,无值抛指定异常
String s4 = opt.orElseThrow(() -> new RuntimeException("No value"));

判断与过滤

Optional<String> opt = Optional.of("Hello");
 
// isPresent():是否有值
boolean present = opt.isPresent();  // true
 
// isEmpty():是否为空(Java 11+)
boolean empty = opt.isEmpty();  // false
 
// ifPresent():有值则执行 Consumer
opt.ifPresent(s -> System.out.println(s));
 
// ifPresentOrElse():有值执行 action,无值执行 emptyAction(Java 9+)
opt.ifPresentOrElse(
    s -> System.out.println("Value: " + s),
    () -> System.out.println("No value")
);
 
// filter():过滤
Optional<String> filtered = opt.filter(s -> s.length() > 3);

转换

Optional<String> opt = Optional.of("Hello");
 
// map():转换值
Optional<Integer> len = opt.map(String::length);
 
// flatMap():转换值(返回 Optional)
Optional<String> upper = opt.flatMap(s -> Optional.of(s.toUpperCase()));
 
// or():如果为空,返回另一个 Optional(Java 9+)
Optional<String> result = Optional.<String>empty()
    .or(() -> Optional.of("Default"));

orElse vs orElseGet

方法行为适用场景
orElse()无论有无值都计算默认值默认值是常量或轻量计算
orElseGet()只有无值时才调用 Supplier默认值需要计算或有副作用
// orElse:无论 opt 是否有值,都会执行 getDefaultValue()
String s1 = opt.orElse(getDefaultValue());
 
// orElseGet:只有 opt 为空时才执行
String s2 = opt.orElseGet(() -> getDefaultValue());

实际应用

方法返回值

// 不推荐:返回 null
public User findUser(Long id) {
    return userDao.findById(id);  // 可能返回 null
}
 
// 推荐:返回 Optional
public Optional<User> findUser(Long id) {
    return Optional.ofNullable(userDao.findById(id));
}
 
// 使用
Optional<User> user = userService.findUser(1L);
String name = user.map(User::getName).orElse("Unknown");

链式调用

// 传统 null 检查
User user = getUser();
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        String city = address.getCity();
        if (city != null) {
            System.out.println(city);
        }
    }
}
 
// Optional 链式调用
Optional.ofNullable(getUser())
    .map(User::getAddress)
    .map(Address::getCity)
    .ifPresent(System.out::println);
 
// 带默认值
String city = Optional.ofNullable(getUser())
    .map(User::getAddress)
    .map(Address::getCity)
    .orElse("Unknown");

集合处理

List<User> users = getUsers();
 
// 传统写法
List<String> names = new ArrayList<>();
for (User user : users) {
    if (user.getName() != null) {
        names.add(user.getName());
    }
}
 
// Optional + Stream
List<String> names = users.stream()
    .map(User::getName)
    .filter(Objects::nonNull)
    .collect(Collectors.toList());
 
// 或使用 Optional
List<String> names = users.stream()
    .map(user -> Optional.ofNullable(user.getName()))
    .filter(Optional::isPresent)
    .map(Optional::get)
    .collect(Collectors.toList());

最佳实践

推荐做法

// ✅ 作为方法返回值
public Optional<User> findById(Long id);
 
// ✅ 使用 orElse/orElseGet 提供默认值
String name = user.map(User::getName).orElse("Unknown");
 
// ✅ 使用 ifPresent 处理有值的情况
opt.ifPresent(System.out::println);
 
// ✅ 链式调用避免多层 null 检查
opt.map(A::getB).map(B::getC).orElse(defaultC);

不推荐做法

// ❌ 直接调用 get() 而不检查
String s = opt.get();  // 可能为空时抛异常
 
// ❌ 用作字段或参数
public class User {
    private Optional<String> name;  // 不推荐
}
 
// ❌ 在集合中使用
List<Optional<String>> list;  // 不推荐
 
// ❌ 使用 isPresent + get 组合
if (opt.isPresent()) {
    String s = opt.get();  // 不如直接用 ifPresent/orElse
}

Java 9+ 增强

// ifPresentOrElse(Java 9+)
opt.ifPresentOrElse(
    value -> System.out.println("有值: " + value),
    () -> System.out.println("无值")
);
 
// or(Java 9+)
Optional<String> result = opt.or(() -> Optional.of("默认值"));
 
// stream(Java 9+)
Stream<String> stream = opt.stream();  // 有值返回单元素流,无值返回空流
 
// 示例:过滤掉空的 Optional
List<Optional<String>> optionals = Arrays.asList(
    Optional.of("a"),
    Optional.empty(),
    Optional.of("b")
);
List<String> values = optionals.stream()
    .flatMap(Optional::stream)
    .collect(Collectors.toList());
// ["a", "b"]

面试要点总结

问题答案要点
Optional 作用?优雅处理空值,避免 NPE
创建方式?empty()、of()、ofNullable()
orElse vs orElseGet?orElse 总是计算,orElseGet 懒加载
map vs flatMap?map 返回值,flatMap 返回 Optional
推荐用法?作为返回值、链式调用、提供默认值
不推荐用法?作为字段、集合元素、直接 get()

参考资料