Optional 使用指南
·
Optional 是 Java 8 引入的一个容器类,用于表示一个值可能存在或不存在。它是一种更优雅的方式来处理可能为 null 的值。Optional 本质上是一个包装器,用于放置可能为空的值,它可以合理而优雅地处理 null。
历史背景:null 在编程历史上极具话题性,号称是"计算机历史上最严重的错误"。Optional 的出现使 Java 对 null 的表达能力更近了一步。

为什么需要 Optional
传统方式的问题
// 传统方式 - 容易出现 NullPointerException,嵌套判断导致代码臃肿
public String getUserEmail(Long userId) {
User user = userRepository.findById(userId);
if (user != null) {
Address address = user.getAddress();
if (address != null) {
String email = address.getEmail();
if (email != null) {
return email;
}
}
}
return "未知";
}
Optional 方式 - 函数式链式调用
// Optional 方式 - 更清晰、更安全、更简洁
public String getUserEmail(Long userId) {
return userRepository.findById(userId)
.map(User::getAddress)
.map(Address::getEmail)
.orElse("未知");
}

Optional 的结构

创建 Optional 对象
三种创建方式对比

代码示例与注意事项
// 1. Optional.of() - 值不能为 null,否则抛出 NullPointerException
Optional<String> opt1 = Optional.of("Hello");
// Optional<String> opt1 = Optional.of(null); // ❌ 会抛出 NPE!
# 2. Optional.ofNullable() - 值可以为 null(推荐)
Optional<String> opt2 = Optional.ofNullable(null); // ✅ 返回 empty Optional
Optional<String> opt3 = Optional.ofNullable("Hello"); // ✅ 返回包含值的 Optional
// 3. Optional.empty() - 创建空的 Optional(业务返回值推荐)
public Optional<User> findUser(String name) {
if (StringUtils.isEmpty(name)) {
return Optional.empty(); // ✅ 明确返回空,而不是 null
}
return Optional.ofNullable(userRepository.findByName(name));
}
常用方法详解
API 推荐度速查表
| 方法 | 推荐度 | 说明 |
|---|---|---|
empty() |
⭐⭐⭐⭐ | 替代返回 null |
of(T) |
⭐⭐ | 需要确保值非空 |
ofNullable(T) |
⭐⭐⭐⭐⭐ | 最常用的创建方式 |
get() |
⭐ | 尽量避免直接使用 |
orElse(T) |
⭐⭐ | 适用于静态默认值 |
orElseGet(Supplier) |
⭐⭐⭐⭐⭐ | 推荐用于获取值 |
orElseThrow(Supplier) |
⭐⭐⭐⭐ | 阻塞性场景推荐 |
isPresent() |
⭐⭐⭐ | 避免用于 if 判断 |
ifPresent(Consumer) |
⭐⭐⭐⭐ | 替代 if-get 模式 |
map(Function) |
⭐⭐⭐⭐⭐ | 链式转换核心方法 |
flatMap(Function) |
⭐⭐⭐⭐⭐ | 避免嵌套 Optional |
filter(Predicate) |
⭐⭐⭐⭐ | 条件过滤 |
1. 检查值是否存在
Optional<String> opt = Optional.of("Hello");
// Java 8+ - 避免在 if 判断中使用
if (opt.isPresent()) {
System.out.println(opt.get()); // ❌ 反模式
}
// Java 11+ - isEmpty()
if (opt.isEmpty()) {
System.out.println("值不存在");
}
// ✅ 推荐方式:使用 ifPresent
opt.ifPresent(System.out::println);
2. 获取值:orElse vs orElseGet

// 性能对比示例
public String getName() {
System.out.println("方法被调用了"); // 用于观察执行情况
return "默认名称";
}
Optional<String> opt = Optional.of("存在的值");
// ❌ orElse - 无论如何都会执行 getName()
String name1 = opt.orElse(getName());
// 输出:方法被调用了
// 结果:name1 = "存在的值"(但 getName() 白白执行了)
// ✅ orElseGet - 只在值不存在时才执行
String name2 = opt.orElseGet(() -> getName());
// 无输出(因为 opt 有值,Supplier 不会执行)
// 结果:name2 = "存在的值"
// 使用场景区分
public static final String DEFAULT_STATUS = "UNKNOWN"; // 静态常量
// ✅ 返回静态资源时使用 orElse
String status1 = opt.orElse(DEFAULT_STATUS); // 推荐
// ❌ 不要每次都创建新对象
String status2 = opt.orElse("UNKNOWN"); // 每次都会创建新 String
// ✅ 涉及方法调用、远程调用、IO 操作时使用 orElseGet
User user = userOpt.orElseGet(() -> remoteService.getDefaultUser());
String config = configOpt.orElseGet(() -> loadFromFile());
3. 条件操作
Optional<String> opt = Optional.of("Hello");
// ifPresent - 如果值存在则执行操作(替代 if-get 模式)
opt.ifPresent(value -> System.out.println(value));
// Java 9+ ifPresentOrElse - 同时处理存在和不存在的情况
opt.ifPresentOrElse(
value -> System.out.println("存在: " + value),
() -> System.out.println("不存在")
);
// ❌ 反模式:不要这样写
if (opt.isPresent()) {
System.out.println(opt.get());
}
// ✅ 正确做法
opt.ifPresent(System.out::println);
4. 转换操作:map vs flatMap

Optional<String> name = Optional.of("john");
// map - 转换值(函数返回普通类型)
Optional<String> upperName = name.map(String::toUpperCase); // JOHN
Optional<Integer> length = name.map(String::length); // 4
// flatMap - 避免 Optional<Optional<T>>(函数返回 Optional)
// 假设 Teacher 类有 Address 字段,Address 类有 City 字段
// ❌ 使用 map 会导致嵌套
Optional<Optional<Address>> nested =
Optional.ofNullable(teacher).map(Teacher::getAddress);
// ✅ 使用 flatMap 扁平化
Optional<String> city = Optional.ofNullable(teacher)
.flatMap(t -> Optional.ofNullable(t.getAddress()))
.flatMap(a -> Optional.ofNullable(a.getCity()));
// 或者更简洁(如果 getter 返回 Optional)
Optional<String> city2 = Optional.ofNullable(teacher)
.flatMap(Teacher::getAddress)
.flatMap(Address::getCity);
// filter - 过滤
Optional<String> filtered = name
.filter(s -> s.length() > 3) // 通过
.filter(s -> s.startsWith("j")); // 通过
5. 抛出异常:orElseThrow
// 阻塞性业务场景:必须获取到值才能继续
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("用户不存在: " + id));
}
// Java 10+ 可以省略参数(抛出 NoSuchElementException)
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(); // 抛出 NoSuchElementException
}
6. 链式调用综合示例
public Optional<String> getUserCityName(Long userId) {
return userRepository.findById(userId)
.filter(User::isActive) // 过滤非活跃用户
.map(User::getAddress) // Optional<Address>
.filter(Address::isValid) // 过滤无效地址
.map(Address::getCity) // Optional<City>
.map(City::getName) // Optional<String>
.filter(name -> !name.isEmpty()); // 过滤空名称
}
最佳实践
基本原则

1. 返回值使用 Optional(✅ 推荐)

// ✅ 好的实践:明确表示返回值可能为空
public Optional<User> findUserById(Long id) {
return userRepository.findById(id);
}
// 调用方可以清晰地处理空值
Optional<User> userOpt = service.findUserById(1L);
userOpt.ifPresent(user -> System.out.println(user.getName()));
// ❌ 不推荐:返回 null 给调用方带来负担
public User findUserById(Long id) {
return userRepository.findById(id); // 可能返回 null
}
2. 不要在字段中使用 Optional(❌ 反模式)
// ❌ 不推荐:序列化问题、占用额外内存
public class User {
private Optional<String> nickname; // 不要这样做
private Optional<Address> address; // 不要这样做
}
// ✅ 推荐:字段可为 null,通过 getter 返回 Optional
public class User {
private String nickname; // 可以为 null
private Address address; // 可以为 null
public Optional<String> getNickname() {
return Optional.ofNullable(nickname);
}
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
}
3. 不要用于方法参数(❌ 反模式)
// ❌ 不推荐:增加调用复杂度
public void setUserType(Optional<UserType> userType) {
this.userType = userType.orElse(UserType.NORMAL);
}
// ✅ 推荐:使用方法重载
public void setUserType(UserType userType) {
this.userType = userType != null ? userType : UserType.NORMAL;
}
// 或者提供多个重载方法
public void createUser(String name) {
createUser(name, null);
}
public void createUser(String name, UserType userType) {
// 实现逻辑
}
4. 不要在集合中使用 Optional(❌ 反模式)
// ❌ 不推荐:集合本身就能表达空
List<Optional<String>> list = new ArrayList<>();
Map<String, Optional<User>> map = new HashMap<>();
// ✅ 推荐:直接使用集合的空表达
List<String> list = new ArrayList<>(); // 空列表本身就是空的表达
Map<String, User> map = new HashMap<>(); // 使用 getOrDefault()
User user = map.getOrDefault("key", defaultUser);
5. 合理使用 orElse 和 orElseGet
// 静态常量
public static final String DEFAULT_STATUS = "UNKNOWN";
public static final User GUEST_USER = new User("Guest");
// ✅ 静态资源用 orElse
String status = Optional.ofNullable(getStatus()).orElse(DEFAULT_STATUS);
User user = Optional.ofNullable(getUser()).orElse(GUEST_USER);
// ✅ 方法调用、计算、IO 操作用 orElseGet
String config = configOpt.orElseGet(() -> loadConfigFromFile());
User admin = userOpt.orElseGet(() -> createDefaultAdmin());
String data = dataOpt.orElseGet(() -> fetchFromRemote());
常见反模式
反模式速查表
| 反模式 | 问题 | 正确做法 |
|---|---|---|
if (opt.isPresent()) opt.get() |
等同于判空,失去 Optional 意义 | 使用 ifPresent() 或 orElse() |
返回 null 的 Optional |
违背 Optional 设计初衷 | 返回 Optional.empty() |
| 字段使用 Optional | 序列化问题、内存浪费 | 字段为普通类型,getter 返回 Optional |
| 参数使用 Optional | 增加调用复杂度 | 使用方法重载或直接传 null |
| 过度包装简单判空 | 增加代码复杂度 | 简单场景直接判空 |
直接使用 get() |
可能抛出 NoSuchElementException |
使用 orElse 系列方法 |
1. 不要使用 isPresent() + get()
// ❌ 反模式:本质上还是 if-null 判断
if (opt.isPresent()) {
String value = opt.get();
System.out.println(value);
} else {
System.out.println("默认值");
}
// ✅ 正确做法 1:使用 ifPresent
opt.ifPresent(System.out::println);
// ✅ 正确做法 2:使用 ifPresentOrElse (Java 9+)
opt.ifPresentOrElse(
System.out::println,
() -> System.out.println("默认值")
);
// ✅ 正确做法 3:使用 orElse
String value = opt.orElse("默认值");
System.out.println(value);
2. 不要返回 null 的 Optional
// ❌ 反模式:永远不要返回 null
public Optional<User> findUser(Long id) {
if (id == null) {
return null; // ❌ 这违背了 Optional 的设计初衷
}
return userRepository.findById(id);
}
// ✅ 正确做法:返回 empty Optional
public Optional<User> findUser(Long id) {
if (id == null) {
return Optional.empty(); // ✅ 明确表示没有值
}
return userRepository.findById(id);
}
3. 避免过度使用
// ❌ 过度使用:简单场景反而更复杂
String name = Optional.ofNullable(user)
.map(User::getName)
.orElse("未知");
// ✅ 简单情况直接判空更清晰
String name = user != null ? user.getName() : "未知";
// ✅ Optional 适合复杂的链式调用
String cityName = Optional.ofNullable(user)
.map(User::getAddress)
.filter(Address::isValid)
.map(Address::getCity)
.map(City::getName)
.orElse("未知");
性能考量
orElse vs orElseGet 性能对比
@Test
public void performanceTest() {
Optional<String> opt = Optional.of("value");
// orElse - 总是执行,即使有值
long start1 = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
opt.orElse(expensiveOperation()); // expensiveOperation 总是执行
}
long time1 = System.nanoTime() - start1;
// orElseGet - 只在没有值时执行
long start2 = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
opt.orElseGet(() -> expensiveOperation()); // 不会执行
}
long time2 = System.nanoTime() - start2;
System.out.println("orElse: " + time1 + " ns");
System.out.println("orElseGet: " + time2 + " ns");
// orElseGet 性能明显优于 orElse
}
Optional 的开销
// Optional 会创建额外对象,在性能敏感场景需要考虑
// ❌ 不推荐:在循环中大量创建 Optional
for (int i = 0; i < 1000000; i++) {
Optional<String> opt = Optional.ofNullable(getValue(i));
opt.ifPresent(this::process);
}
// ✅ 推荐:直接判空
for (int i = 0; i < 1000000; i++) {
String value = getValue(i);
if (value != null) {
process(value);
}
}
Optional 方法流程图

实际应用场景
场景 1: 数据库查询
// Repository 层返回 Optional
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findById(Long id);
Optional<User> findByEmail(String email);
}
// Service 层处理 Optional
public String getUserEmailOrDefault(Long userId) {
return userRepository.findById(userId)
.map(User::getEmail)
.filter(email -> email.contains("@"))
.orElse("no-email@example.com");
}
// Controller 层
public UserDTO getUserInfo(Long userId) {
return userService.findById(userId)
.map(this::convertToDTO)
.orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
}
场景 2: 配置读取
public class ConfigService {
private Map<String, String> configMap = new HashMap<>();
// 返回 Optional 明确表示配置可能不存在
public Optional<String> getConfig(String key) {
return Optional.ofNullable(configMap.get(key));
}
// 使用方可以灵活处理
public int getTimeout() {
return getConfig("timeout")
.map(Integer::parseInt)
.filter(v -> v > 0)
.orElseGet(() -> getDefaultTimeout());
}
public String getDatabaseUrl() {
return getConfig("db.url")
.orElseThrow(() -> new ConfigurationException("缺少数据库配置"));
}
}
场景 3: Stream 操作结合
public Optional<User> findFirstAdminUser() {
return userList.stream()
.filter(User::isAdmin)
.filter(User::isActive)
.findFirst(); // 返回 Optional<User>
}
// 链式处理
public String getFirstAdminEmail() {
return userList.stream()
.filter(User::isAdmin)
.findFirst()
.map(User::getEmail)
.orElse("admin@example.com");
}
场景 4: 复杂业务逻辑
public class OrderService {
// 获取订单的收货地址城市名称
public Optional<String> getOrderShippingCity(Long orderId) {
return orderRepository.findById(orderId)
.filter(Order::isPaid) // 只处理已支付订单
.map(Order::getShippingAddress) // 获取收货地址
.filter(Address::isComplete) // 地址信息完整
.map(Address::getCity) // 获取城市
.filter(city -> !city.trim().isEmpty()); // 城市名称非空
}
// 使用示例
public void processOrder(Long orderId) {
getOrderShippingCity(orderId)
.ifPresentOrElse(
city -> shippingService.sendToCity(city),
() -> notificationService.notifyIncompleteAddress(orderId)
);
}
}
总结
Optional 的核心优势

使用指南总结
何时使用 Optional:
- ✅ 作为方法的返回值类型
- ✅ 处理可能为空的业务逻辑
- ✅ 需要链式调用和函数式编程风格
- ✅ 明确表达"值可能不存在"的语义
何时不使用 Optional:
- ❌ 不要用作类的成员变量
- ❌ 不要用作方法参数
- ❌ 不要用在集合元素中
- ❌ 简单的判空场景(过度设计)
- ❌ 性能敏感的高频调用
记住这些要点
- Optional 不是银弹:它是为了更好地表达"可能没有值"的语义,而不是替代所有的 null 检查
- **优先使用 **
orElseGet:避免orElse的性能陷阱 - **避免 **
isPresent() + get():使用ifPresent、map、orElse等方法 - 永远不要返回 null:返回
Optional.empty() - 合理使用:在适合的场景使用,不要过度设计
最佳实践总结:Optional 让空值处理更加优雅和安全,但需要理解其设计意图和使用场景,避免滥用。合理使用可以大大提升代码质量,减少 NPE,节省大量调试时间。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)