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() |
参考资料
- Optional 类文档 (opens in a new tab)
- 《Java 8 实战》