一个可以用来存储空值和非空值的容器,旨在优雅地处理可能为
null
的值 ,从而减少NullPointerException
的发生,提高代码的可读性和健壮性。
封包行为
“封包行为 ”指的是将一个值封装进 Optional
容器中,返回值为Option<T>
使其成为一个可显式表达“值可能存在或缺失”的对象。这种封装是使用 Optional
的第一步,也是后续链式调用和解包操作的基础。
Optional.of(T value)
将一个非空值封装为 Optional
。
-
如果
value != null
,返回一个包含该值的Optional
。 -
如果
value == null
,抛出NullPointerException
。 -
使用场景
- 确保值一定不为
null
时使用。
- 确保值一定不为
Optional.ofNullable(T value)
将一个可能为 null
的值封装为 Optional
。
- 如果
value != null
,返回一个包含该值的Optional
。 - 如果
value == null
,返回一个空的Optional
(即Optional.empty()
)。 - 使用场景
- 值可能为
null
,需要安全封装时使用。
- 值可能为
解包行为
Optional
的核心设计目标之一是显式处理值是否存在 ,因此它提供了多种“解包”方法来安全地获取内部值或处理缺失值的情况 。以下是 Optional
中所有用于解包的常见方法及其使用场景和区别:
get
T get()
直接获取值(如果存在)。
- 如果值存在,返回值。不存在(即
Optional
为空),抛出NoSuchElementException
。 - 不推荐直接使用 ,因为容易抛出异常。
Optional<User> optionalUser = Optional.of(new User("Alice"));
User user = optionalUser.get(); // 返回 Alice
orElseThrow
T orElseThrow(Supplier<? extends X> exceptionSupplier)
如果值存在,返回值;否则抛出指定异常。
- 可以自定义异常类型和信息,适合业务逻辑中主动抛异常(推荐)
User user = Optional.ofNullable(findUserById(123))
.orElseThrow(() -> new RuntimeException("用户不存在"));
orElse
T orElse(T other)
如果值存在,返回值;否则返回默认值 other
。
- 默认值简单且计算成本低时使用。(立刻计算)
String name = Optional.ofNullable(user.getName()).orElse("Unknown");
orElseGet
T orElseGet(Supplier<? extends T> supplier)
如果值存在,返回值;否则调用 supplier
生成默认值。
- 默认值计算成本较高(如读取文件、调用数据库等),调用
supplier
延迟生成默认值(惰性求值 )。
String name = Optional.ofNullable(user.getName())
.orElseGet(() -> loadDefaultNameFromDB());
ifPresent
void ifPresent(Consumer<? super T> consumer)
如果值存在,执行 consumer
操作,如果值不存在,不做任何操作。
- 值存在时需要执行某些副作用(如赋值、打印日志等)。
Optional.ofNullable(user).ifPresent(u -> System.out.println("User found: " + u.getName()));
使用场景
场景一:对象存在性检查 + 条件操作
当对象存在时,执行某个操作(如赋值、打印等),否则忽略。
Optional.ofNullable(user).ifPresent(u->u.setName("aciu"));
场景二:条件过滤 + 异常抛出
对对象进行条件验证,若不满足条件则抛出异常。
return Optional.ofNullable(user)
.filter(s -> !isEmpty(s.getName()))
.orElseThrow(() -> new BizException("查询不到该记录"));
场景三:链式属性访问 + 安全获取嵌套值
从多级嵌套对象中安全获取属性值,避免中间对象为 null 导致空指针。
Optional.ofNullable(comp)
.map(Competition::getResult)
.map(CompResult::getChampion)
.map(User::getName)
.orElseThrow(() -> new IllegalArgumentException(...));
场景四:配置解析 + 默认值处理
从配置或外部数据源获取值,若值缺失或转换失败则使用默认值。
int timeout = Optional.ofNullable(redisProperties.getTimeout())
.map(x -> Long.valueOf(x.toMillis()).intValue())
.orElse(10000);
不推荐场景
- 不推荐作为类的字段(不可序列化、内存开销)。
- 不推荐用于方法参数(应由调用者保证合法性)。
- 高频调用的代码块(轻微性能开销)。