这篇文章主要结合源码去理解学习Optional类,本人能力有限,或许有些地方不能理解,希望能有大佬解惑
java8 引入了一个比较有趣的特性--Optional类,ta主要用来解决空指针异常的问题
1.创建Optional
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
由于Optional类中构造方法都是private权限的 所以只能根据下列方法获取Optional实例
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
empty() 创建一个value为null的的实例,(@SuppressWarnings("unchecked") 为忽略警告,在这里我们不要管他)
of(T value) 内部调用了构造函数,通过查看构造函数,发现调用了Objects.requireNonNull(value),检查是否为空,如果为空抛出 NullPointerException,所以我们可以得出结论: of() 只能创建非空值,当确定value不为null时,我们才能通过 Optional.of(value) 来得到包含value的Optional实例
ofNullable(T value) 通过方法内部代码可以看出和of(T value)的区别只是当value为 null 时,ofNullable返回EMPTY对象
由此可以看出,在开发中用到ofNullable的机会比of大很多
代码:
Optional<Object> empty = Optional.empty();
Optional<String> _nonNull = Optional.of("_NonNull");
Optional<Object> _null = Optional.ofNullable(null);
补充:Optional其实就是一个包装类,可以装空值和非空值,可以解决很多场景下的空指针异常
2.访问Optional
@NotNull @Contract(pure=true)public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; } public boolean isPresent() { return value != null; } public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); } public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); } public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } } public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } } public T orElse(T other) { return value != null ? value : other; } public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
@NotNull @Contract(pure=true) 为什么会出现在这里?
代码都很简单
get() 获取值,空值抛异常
isPresent() 判断值是否存在
ifPresent(Consumer<? super T> consumer)传入一个消费者,如果值存在就执行lambda表达式
filter(Predicate<? super T> predicate) 传入谓词进行过滤,如果value满足条件则返回,不满足返回EMPTY
map(Function<? super T, ? extends U> mapper),flatMap(Function<? super T, Optional<U>> mapper) 两个方法都是对Optional中的值进行一系列操作,通过实现Function的lambda表达式传入操作,通过源码可以看出,二者都要求Optional的值非空才能执行mapping函数,二者都返回Optional对象,但map会自动将结果封装为Optional对象,flatMap则需要手动封装到Optional
orElse(T other),orElseGet(Supplier<? extends T> other) 设置默认值,当value为空时,orElse返回参数值,orElseGet返回Supplier接口的执行结果,当value有值时,二者都返回value,区别在于orElse的默认值为参数,即在调用orElse时默认值已经存在,而orElseGet默认值是接口实现生成,参数为生成默认值的手段,即当调用orElseGet时,默认值还没有生成,只提供了生成默认值的方法,在value为空时才生成默认值。
orElseThrow(Supplier<? extends X> exceptionSupplier) 当value为空时,抛出异常,自己决定抛出异常类型,而不是总抛出NullPointerException
_nonNull.ifPresent(System.out::println);
Optional<Boolean> aBoolean = _nonNull.map(non -> non.contains("o"));
Optional<Boolean> aBoolean1 = aBoolean.filter(Boolean::booleanValue);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具