Optional< T >
- [📌 一句话总结](#📌 一句话总结)
- [📝 详细总结](#📝 详细总结)
-
- [1. 🔍 为什么要用 Optional?](#1. 🔍 为什么要用 Optional?)
- [2. 🛠️核心构造方法](#2. 🛠️核心构造方法)
- [3. 🛠️ 常用操作方法](#3. 🛠️ 常用操作方法)
- [4. 最佳实践建议](#4. 最佳实践建议)
- [5. 💻 代码示例对比](#5. 💻 代码示例对比)
- [⚠️ 最佳实践与避坑指南](#⚠️ 最佳实践与避坑指南)
- [💡 总结](#💡 总结)
📌 一句话总结
Optional 是 Java 8 引入的一个容器类,代表一个值可能存在也可能不存在,它的核心目的是优雅地处理 null 值,避免空指针异常。
📝 详细总结
在 Java 8 之前,我们通常用 null 来表示"没有值",但这很容易导致著名的 NullPointerException (空指针异常)。Optional 的引入就是为了通过设计模式强制调用者去处理"值不存在"的情况,从而避免这类运行时错误。
Optional 的设计初衷是为了解决 Java 程序中频繁出现的 NullPointerException。它通过强制开发者显式地处理"值为空"的情况,从而让代码更加健壮和清晰。
1. 🔍 为什么要用 Optional?
在 Java 8 之前,我们通常直接返回 null 来表示"没有找到对象"。
问题:调用者很容易忘记判空,直接调用方法导致程序崩溃。
解决:Optional 就像一个"有盖子的盒子"。它明确告诉调用者:"这里面可能没东西,你必须打开盖子检查一下才能用"。
Optional 的核心作用:
它不是一个集合,也不是为了完全替代 null,而是作为一种API 设计的返回类型,向调用者明确传达:"这个方法可能找不到你要的对象"。
2. 🛠️核心构造方法
你不能直接 new 一个 Optional,通常使用以下静态工厂方法创建:
Optional.empty():创建一个空的 Optional 对象(盒子是空的)。
Optional.of(value):包装一个非 null 的值。如果传入的值是 null,会立即抛出空指针异常(用于保护)。
Optional.ofNullable(value):包装一个可能为 null 的值。如果值为 null,它会自动返回 empty(),这是最常用的方法。
3. 🛠️ 常用操作方法
拿到 Optional 对象后,你不能直接使用它(比如调用 T.getName()),必须先从"盒子"里把东西取出来你需要通过以下方法来"开箱"或处理数据:
| 方法类型 | 常用方法 | 作用与场景 |
|---|---|---|
| 判断 | isPresent() |
判断值是否存在,返回 true / false。 |
| 安全消费 | ifPresent(Consumer) |
推荐。如果值存在,就执行某个操作(如打印、赋值);不存在则跳过,无需写 if 语句。 |
| 获取值 | get() |
慎用。直接获取值,但如果 Optional 为空,会抛出异常。 |
| 提供默认值 | orElse(T other) |
如果值存在就返回值,否则返回传入的默认值(例如 orElse(new User()))。 |
| 延迟提供默认值 | orElseGet(Supplier) |
与 orElse 类似,但参数是一个函数式接口。只有在值为空时才会执行该函数(懒加载,性能更好)。 |
| 抛出异常 | orElseThrow(Supplier) |
推荐。如果值为空,抛出自定义的异常(如 new ResourceNotFoundException())。 |
| 值转换 | map(Function) |
如果值存在,将其转换为另一种类型。例如:从 Optional<User> 转为 Optional<String>(获取用户名)。 |
4. 最佳实践建议
✅ 推荐:用作方法的返回类型。这能让 API 的使用者清楚地知道这个返回值可能为空。
❌ 不推荐:
作为类的成员变量(字段)。
作为方法的参数。
在集合中使用(如 List<Optional>)。
在多线程环境中作为共享变量。
5. 💻 代码示例对比
传统写法(容易出错):
java
User user = getUserFromDB(id);
// 如果忘记判空,这里可能报错
String name = user.getName();
Optional 写法(安全且优雅):
java
Optional<User> optionalUser = getUserFromDB(id);
// 方式1:如果存在就打印
optionalUser.ifPresent(user -> System.out.println(user.getName()));
// 方式2:获取名字,如果用户不存在就叫"匿名"
String name = optionalUser.map(User::getName).orElse("匿名");
// 方式3:如果不存在就抛出异常
User user = optionalUser.orElseThrow(() -> new UserNotFoundException("用户不存在"));
⚠️ 最佳实践与避坑指南
不要用它作为类的字段:
Optional 没有实现 Serializable 接口,不适合作为实体类(Entity)的属性,也不建议作为方法参数传递。
避免直接调用 get():
get() 方法在值为空时会直接抛出 NoSuchElementException。除非你 100% 确定值存在,否则请使用 orElse 或 ifPresent。
避免链式判断:
不要写成 if (optional.isPresent()) { optional.get() },这又回到了以前判空的老路上,失去了 Optional 的意义。直接用 ifPresent 或 map。
总结来说,Optional 是一种更优雅、更安全的处理"可能缺失对象"的方式,它让你的代码意图更清晰,减少了空指针异常的风险。
💡 总结
Optional 不是 null 的完全替代品,而是一种设计工具。它通过函数式编程的思想,让你的代码在处理可能缺失的值时,更加清晰、安全且具有可读性。