Java8新特性之Optional类
时间:2022-07-22
本文章向大家介绍Java8新特性之Optional类,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
从 Java 8 引入的一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都非常了解的异常。
简单的示例
我们从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 NullPointerException:
String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();
在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
if (isocode != null) {
isocode = isocode.toUpperCase();
}
}
}
}
你看到了,这很容易就变得冗长,难以维护。
学习 Optional 类
位置:package java.util; 类名:Optional
public final class Optional<T> {
/**
* 创建出一个Optional容器,容器里面没有装载着对象
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* 容器中的对象
*/
private final T value;
/**
* 私有的构造方法
*/
private Optional() {
this.value = null;
}
/**
* 得到一个Optional容器,Optional没有装载着对象
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
* 私有构造方法(带参数),参数就是具体的要装载的对象,如果传进来的对象为null,则抛出异常
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
/**
* 创建出Optional容器,并将对象(value)装载到Optional容器中
*
* 传入的value如果为null,则抛出异常(调用的是Optional(T value)方法)
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
* 创建出Optional容器,并将对象(value)装载到Optional容器中
*
* 传入的value可以为null,如果为null,返回一个没有装载对象的Optional对象
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/**
* 得到容器中的对象,如果为null就抛出异常
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* 判断容器中的对象是否为null
*/
public boolean isPresent() {
return value != null;
}
/**
* 如果存在某个值,则使用该值调用指定的使用者,否则不执行任何操作
* 该方法除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式
*/
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
/**
* 如果容器中的对象存在,并且符合过滤条件,返回装载对象的Optional容器,否则返回一个空的Optional容器
*/
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
/**
* 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的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));
}
}
/**
* flatMap方法与map方法类似,区别在于apply函数的返回值不同。map方法的apply函数返回值是 ? extends U,而flatMap方法的apply函数返回值必须是Optional
*/
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;
}
/**
* 如果对象存在,则直接返回,否则返回由Supplier(供应者) 函数式接口的实现用来生成默认值
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
/**
* 如果存在,则返回。否则抛出Supplier(供应者) 函数式接口创建的异常
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}
ofNullable() 与 of()
创建Optional容器有两种方式
- 调用ofNullable()方法,传入的对象可以为null
- 调用of()方法,传入的对象不可以为null,否则抛出NullPointerException
@Test
void test1() {
User user = new User();
User userNull = null;
Optional<User> user2 = Optional.of(user);
//Optional<User> user3 = Optional.of(userNull); // 抛出NullPointerException
Optional<User> user3 = Optional.ofNullable(userNull);
}
orElse()
如果容器中的对象存在,则返回。否则返回传递进来的参数
@Test
void test2() {
User user = new User("1", "Ray", "123456");
User userNull = null;
Optional<User> user2 = Optional.ofNullable(user);
Optional<User> user3 = Optional.ofNullable(userNull);
System.out.println(user2.orElse(null));
System.out.println(user3.orElse(null));
}
ifPresent()
进阶用法(主要是因为函数式编程,简化代码)
源码
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
----------------------------
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
用法
@Test
void test3() {
User user = new User("1", "Ray", "123456");
// ifPresent 写法
Optional<User> user2 = Optional.ofNullable(user);
user2.ifPresent((s -> System.out.println(s.getName())));
System.out.println("------- 结果是一样的 --------");
// 旧的写法
if (null != user) {
System.out.println(user.getName());
}
}
orElseGet()
如果对象存在,则直接返回,否则返回由Supplier接口的实现用来生成默认值
@Test
void test4() {
User user = new User("1", "Ray", "123456");
Optional<User> optional = Optional.ofNullable(user);
// orElseGet 写法
User user1 = optional.orElseGet(() -> new User());
System.out.println("------- 结果是一样的 --------");
// 旧的写法
if (null != user) {
user = new User();
}
}
如果存在user,则直接返回,否则创建出一个新的User对象
filter()
源码
// 如果容器中的对象存在,并且符合过滤条件,返回装载对象的Optional容器,否则返回一个空的Optional容器
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
// 接口
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
用法
@Test
void test5() {
User user = new User("1", "Ray", "123456");
Optional<User> optional = Optional.ofNullable(user);
// filter 写法
User user1 = optional.filter((value) -> "Ray".equals(value.getName())).orElse(null);
System.out.println("user1 = " + user1);
System.out.println("------- 结果是一样的 --------");
if (null != user) {
if ("Ray".equals(user.getName())) {
System.out.println("user1 = " + user1);
} else {
System.out.println("user1 = " + user1);
}
}
}
map()
源码
// 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的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));
}
}
// 接口
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
用法
@Test
void test6() {
User user = new User("1", "Ray", "123456");
Optional<User> optional = Optional.ofNullable(user);
// 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的Optional,否则返回空Optional。
String name = optional.map(user1 -> user1.getName()).orElse("Ray");
System.out.println("name = " + name);
System.out.println("------- 结果是一样的 --------");
if (null != user) {
System.out.println("name = " + user.getName());
} else {
System.out.println("name = Ray");
}
}
总结
再来感受一下Optional的魅力
/**
* 以前的代码 1.0
*/
public static String version1(User user) {
if (user != null) {
String name = user.getName();
if (name != null) {
return name.toUpperCase();
} else {
return null;
}
} else {
return null;
}
}
/**
* 以前的代码 2.0
*/
public static String version2(User user) {
if (user != null && StringUtils.isNotBlank(user.getName())) {
return user.getName().toUpperCase();
}
return null;
}
/**
* 现在的代码 3.0
*/
public static String version3(User user) {
return Optional.ofNullable(user)
.map(user1 -> user1.getName())
.map(s -> s.toUpperCase())
.orElse(null);
}
filter,map或flatMap一个函数,函数的参数拿到的值一定不是null。所以我们通过filter,map 和 flatMap之类的函数可以将其安全的进行变换,最后通过orElse系列,get,isPresent 和 ifPresent将其中的值提取出来。
- 渗透测试时,需要注意浏览器选项
- 码云 Android apk 在线构建功能上线啦
- addslashes防注入的绕过案例(AFSRC获奖白帽子情痴)
- Hive表字段Comment中文乱码
- 在Win10上是用Anaconda搭建TensorFlow开发环境
- A Gentle Introduction to Autocorrelation and Partial Autocorrelation (译文)
- A Gentle Introduction to Applied Machine Learning as a Search Problem (译文)
- 技术创新,基于 React Native 的开源项目 | 码云周刊第 17 期
- How to Use the TimeDistributed Layer for Long Short-Term Memory Networks in Python 译文
- ssctf2017_WriteUp
- CENTOS7.2安装CDH5.10和Kudu1.2(一)
- Docker镜像管理
- 360春秋杯3道web题的简单分析
- Vue 2.0 学习总结,精华全在这里了
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- sddm启动root登陆kde By HKL, Tuesd
- ELK收集处理Huawei/H3C交换机日志 By HKL,
- UniFi Register Device with keadhcp By HKL,
- Huawei esight to 钉钉dingding (RESTful API) By HKL,
- ngrokc rampis预编译版本 By HKL, Fr
- megacli修复raid1硬盘 By HKL, Tues
- DNSPOD自动更新公网IP脚本 By HKL, Wedn
- Zerotier网卡NAT via iptables By HKL,
- Github Pages同步到Qcloud腾讯云对象存储COS By HKL,
- 独家 | 探索性文本数据分析的新手教程(Amazon案例研究)
- OpenWRT通过3G Modem加asterisk将GSM通话转为SIP By HKL,
- Coding通过Jenkins生成jekyll并发布到腾讯云对象存储Qcloud COS By HKL,
- mybatis 实用技巧:<trim prefix="where" prefixOverrides="and|or">
- OpenWRT配置Webdav(s)共享文件 By HKL,
- OpenWRT配置Apache Webdav By HKL,