Optional的使用与解析
引言
今天在项目中看到了大量Optional的使用,之前我也了解过Optional,是Java8中的新特性,并且便利地为空指针问题提供了处理方法,可以避免繁琐的if/else。
但是并没有真正在项目中使用过Optional,现在就来详细地学习一下Optional的用法以及源码实现。
构造器方法
- Optional.of(T t) : 创建一个 Optional 实例,t 必须非空
- Optional.empty() : 创建一个空的 Optional 实例
- Optional.ofNullable(T t):t 可以为 null
Optional.of(T t)
/**
* 有参构造
使用描述的值构造一个实例。
参数:值–要描述的非null值
抛出:NullPointerException如果值为null
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
//Objects.java
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
/**
返回一个Optional描述给定的非null值。
参数:value 要描述的值,必须为非null
类型参数:<T> –值的类型
返回值:存在值的Optional,若为null则抛出NullPointerException异常
*/
public static <T> Optional<T> of(T value) {
return new Optional<> (value);
}
Optional.empty()
private static final Optional<?> EMPTY = new Optional<>();
private Optional() {
this.value = null;
}
/**
返回一个空的Optional实例。 此Optional没有值。
类型参数:<T> 不存在的值的类型
返回值:一个空的Optional
api注意:
尽管这样做可能很诱人,但应通过将==与Optional.empty()返回的实例进行比较来避免测试对象是否为空。
不能保证它是一个单例。 而是使用isPresent()
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
Optional.ofNullable(T t)
/**
返回一个描述给定值的Optional ,如果为null ,则返回一个空的Optional,否则返回给定值的Optional 。
参数:值描述的可能为null值
类型参数:<T> –值的类型
返回值:一个Optional与如果指定值是非当前值null ,否则一个空Optional
*/
public static <T> java.util.Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
获取类方法
- T get(): 如果调用对象包含值不为 null,返回该值,否则抛异常
- T orElse(T other) :如果有值则将其返回,否则返回指定的 other 对象
- T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由 Supplier 接口实现提供的对象。
- T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由 Supplier
Optional.get()
/**
如果存在值,则返回该值,否则抛出NoSuchElementException 。
返回值:此Optional描述的非null值
抛出:NoSuchElementException如果不存在任何值
api注意:此方法的首选替代方法是orElseThrow()
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
Optional.orElse(T other)
/**
如果存在值,则返回该值,否则返回other 。
参数:其他–要返回的值(如果不存在任何值)。 可以为null 。
返回值:值(如果存在),否则other
*/
public T orElse(T other) {
return value != null ? value : other;
}
Optional.orElseGet(Supplier<? extends T> other)
/**
如果存在值,则返回该值,否则返回由供应函数supplier产生的结果。
返回值:如果不存在值,且supplier为null,则抛出NullPointerException
*/
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
Optional.orElseThrow(Supplier<? extends X> exceptionSupplier)
/**
与get 方法相同
*/
public T orElseThrow() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
如果存在值,则返回该值,否则抛出由异常提供函数产生的异常。
类型参数:<X> –引发的异常类型
返回值:值(如果存在)
抛出:X –如果不存在任何值NullPointerException如果不存在任何值并且异常提供函数为null
api注意:带有空参数列表的对异常构造函数的方法引用可用作提供者
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
or(Supplier<? extends Optional<? extends T>> supplier)
/**如果值存在时,返回一个Optional描述的值,否则将返回一个Optional产生通过供给功能。
参数:供应商–产生要返回的Optional的供应功能
返回值:返回一个Optional描述此的值Optional ,如果一个值存在,否则Optional所生产的供应功能。
抛出:NullPointerException如果提供的函数为null或产生null结果
* @since 9
*/
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if (isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
判断类方法
- boolean isPresent() : 判断是否包含对象
- void ifPresent(Consumer<? super T> consumer) :如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传给它。
- void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) :如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传给它,否则执行 Runnable 接口的实现代码。
Optional.isPresent()
/**
判断是否存在值
*/
public boolean isPresent() {
return value != null;
}
Optional.ifPresent(Consumer<? super T> consumer)
/**
如果存在值,则使用该值执行给定的操作,否则不执行任何操作。
参数:Consumer要执行的动作
*/
public void ifPresent(Consumer<? super T> action) {
if (value != null) {
action.accept(value);
}
}
Optional.ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
/**
如果存在值,则使用该值执行给定的操作,否则执行给定的基于空的操作。
参数:动作–要执行的动作(如果存在值)emptyAction –要执行的基于空的操作(如果不存在任何值)
抛出:如果存在一个值并且给定的操作为null ,或者不存在任何值并且给定的基于空的操作为null ,
则抛出NullPointerException;
*/
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
过滤类方法
- Optional filter(Predicate<? super predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional。
Optional filter(Predicate<? super predicate)
/**
如果存在一个值,并且该值与给定的(predicate方法)匹配,则返回描述该值的Optional ,否则返回一个空的Optional 。
*/
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
映射类方法
- < U >Optional< U > map(Function<? super T,? extends U> mapper):如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
- < U > Optional< U > flatMap(Function<? super T, Optional< U >> mapper):如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返回一个空的 Optional 对象
< U >Optional< U > map(Function<? super T,? extends U> mapper)
/**
map方法接受一个映射函数参数,返回一个被Optional包装的结果。若结果为空,则返回 空Optional 。
如果映射函数返回null结果,则此方法返回空的Optional
返回值类型:Optional对象
*/
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));
}
}
< U > Optional< U > flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
/**
flatMap 方法则要求入参中的函数式接口返回值本身就是 Optional 对象。
返回值:施加的结果Optional可以映射函数此的值Optional ,如果一个值存在,否则一个空Optional
抛出:NullPointerException如果映射函数为null或返回null结果
*/
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()) {
return empty();
} else {
@SuppressWarnings("unchecked")
Optional<U> r = (Optional<U>) mapper.apply(value);
return Objects.requireNonNull(r);
}
}
项目中的使用
// 若取值为null则为""
String num = a.map(DTO::getA).map(A::getNum).orElse("");
// 若取值为null则为null
Long date = b.map(DTO::getB).map(B::getDate).orElse(null);
Optional的使用与解析的更多相关文章
- log4j源码解析-文件解析
承接前文log4j源码解析,前文主要介绍了log4j的文件加载方式以及Logger对象创建.本文将在此基础上具体看下log4j是如何解析文件并输出我们所常见的日志格式 附例 文件的加载方式,我们就选举 ...
- ButterKnife的使用及其解析
本博客介绍ButterKnife的使用及其源码解析. ButterKnife的使用 ButterKnife简介 添加依赖 在Project级别的build.gradle文件中添加为ButterKnif ...
- Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南
Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南 约定:为方便书写,ProtocolBuffers在下文中将已Protobuf代替. 本指南将向您描述如何使用 ...
- ASP.NET MVC3.0或4.0设置二级域名的方法
之前我就想做二级域名指向同一个IP同一个程序无非是在路由匹配规则上做文章也就是对Url的重写的一种思路.我用了半天时间上网查阅了相关资料并做了Demo测试是完全 以的,在这分享给大家... 假如网站主 ...
- 学习swift从青铜到王者之swift基础部分01
1.1 变量和常量 var 变量名称 = 值(var可以修改) let 常量名称 = 值(let不可以修改) 1.2 基本数据类型 整数类型和小数类型 两种基本数据类型不可以进行隐式转换 var in ...
- spring boot整合mybatis框架及增删改查(jsp视图)
工具:idea.SQLyog 版本:springboot1.5.9版本.mysql5.1.62 第一步:新建项目 第二步:整合依赖(pom.xml) <dependencies> < ...
- Swift 可选(Optionals)类型
Swift 的可选(Optional)类型,用于处理值缺失的情况.可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值". Swfit语言定义后缀?作为命 ...
- 10_SpringBoot更加详细
一. 原理初探 1.1 自动装配 1.1.1 pom.xml spring-boot-dependencies: 核心依赖在父工程中 我们在写入或者引入一些SpringBoot依赖的时候, 不需要指定 ...
- Java 8 Optional 类深度解析
Java 8 Optional 类深度解析 身为一名Java程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法.我们首先要判断这个返回值是否为null,只 ...
- Optional源码解析与实践
1 导读 NullPointerException在开发过程中经常遇到,稍有不慎小BUG就出现了,如果避免这个问题呢,Optional就是专门解决这个问题的类,那么Optional如何使用呢?让我们一 ...
随机推荐
- IPV6改造 华为云如此简单
现在很多企业都在搞这个IPV6改造,说实话这个IPV6改造我这边也不是特别精通,也是通过查阅各种资料来了解IPV6这个东西,下面是我查的一些资料大家可以借鉴一下. IPv6改造三步曲--Vecloud ...
- vue 父子组件之间传值
在vue中父子组件传值是必不可少的,大家必须要学会! 首先父组件向子组件传值: 父组件:比如我们传teacher为index,如果我们传值变量可以使用 : 绑定我们在data中定义的变量. 子组件:为 ...
- 论文发表汇款:SWIFT code跨境汇款 —— 如何向境外账号汇款
如何向境外账号汇款? 有以下几种方式: 对方开通中国金融产品账号或在中国有代理公司:如对方开通中国的银行卡,微信.支付宝,等等,这样其实就不属于跨境汇款了,外国的一些公司已经开设中国的金融产品和银行账 ...
- 解决MobaXterm自动断开连接,亲测有效~
场景: 使用MobaXterm工具通过SSH连接Linux服务器,如果一段时间没有操作,MobaXterm会把连接自动断开,这个设定很是不方便.通过更改下面的设置可以使SSH保持长连接,不会自动断开.
- 一文讲透 FPGA CDC 多bit跨时钟域同步-hand-shanking机制
一.背景 数据的跨时钟域处理是FPGA开发过程中的常见问题,存在两种情况 慢时钟向快时钟同步:只需在快时钟域打两拍即可.其RTL如下: 打拍同步的原理:大家在初学FPGA时,经常听过FPGA中对信号打 ...
- 是时候放弃Scratch了,你有更好的扣叮coding
原创 IT软件部落 IT软件部落 Scratch是由麻省理工学院媒体实验室开发的,拥有一个庞大的全球社区,用户可以在社区中分享和交流自己的作品,适用于全球各个领域,包括学校.社区和个人等. 可是你有没 ...
- VulnStack之ATT&CK实战系列———红队实战(一)
目录 前言 环境搭建 外围打点 信息收集 phpmyadmin全局日志getshell 内网信息收集 msf上线 mimikatz抓取明文密码&hash 域信息收集 横向移动 msf+prox ...
- 数字IC知识点:处理多个时钟
1. 多时钟域 图1.多时钟域 对于工程师来说,开发含多个时钟(见图1)的设计是一种挑战. 这样的设计中可能有以下任何一个,或者全部类型的时钟关系: 时钟的频率不同 时钟频率相同,但相位不同 以上两种 ...
- docker之网络与数据管理
docker默认使用bridge(单主机互联)和overlay(可跨主机互联)两种网络驱动来进行容器的网络管理.如需要,还可以自定义网络驱动插件进行docker容器的网络管理. 1.docker默认网 ...
- 通过NPOI读取 excel指定Sheet 到 DataTable
public static DataTable ReadExcelToDataTable(string fileName, string sheetName = null, bool isFirstR ...