学习Java8中Optional

简介: Optional 类主要是为了解决(NullPointerException)空指针异常 。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。

一、Java8之前访问对象的属性或方法

Java8之前访问对象的属性或方法,会使用到以下方式,以下方式可能会造成空指针异常

Stringcode=user.getAddress().getCountry().getCode().toUpperCase();

在上面的代码中,如果要确保不发生空指针异常必须使用非空判断,如下所示

if (null!=user) {
Addressaddress=user.getAddress();
if (null!=address ) {
Countrycountry=address.getCountry();
if (null!=country ) {
Stringcode=country.getCode();
if (null!=code) {
code=code.toUpperCase();
            }
        }
    }
}

代码变得很冗长,难以维护。并且如果再新增加属性,将会增加更多的if判断。为了简化这个过程,我们来看看用 Optional  类是怎么做的。从创建和验证实例,到使用其不同的方法,并与其它返回相同类型的方法相结合,下面是见证 Optional  奇迹的时刻。

二、创建Optional对象

1. 创建包含空值的Optional

Optional.empty();

Optional.of()/Optional.ofNullable()

你可以使用Optional.of()或ofNullable()方法创建Optional对象,两个方法的区别是,使用Optional.of()方法创建对象时,当参数为null时,调用get()方法,程序会抛出NullPointerException。如下图所示

image.png

使用Optional.ofNullable(),当参数为null时,程序会抛出java.util.NoSuchElementException: No value present 异常。如下图所示

image.png

三、获取Optional对象的值

1. get()方法

使用get()方法,此方法在值为null时,抛出异常

@TestpublicvoidgetOptionValue(){
Stringname="John";
Optional<String>opt=Optional.ofNullable(name);
System.out.println(opt.get());
    }

2. isPresent()

 判断是否有值,再进行后续操作

@TestpublicvoidgetOptionValue(){
Stringname="John";
Optional<String>opt=Optional.ofNullable(name);
if(opt.isPresent()){
System.out.println(opt.get());
        }
    }

3. ifPresent()

   判断是否有值再进行后续操作,接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式

@TestpublicvoidgetOptionValue(){
Stringname="John";
Optional<String>opt=Optional.ofNullable(name);
opt.ifPresent(System.out::println );
    }

四、返回默认值

1. orElse()

orElse()方法,它的工作方式非常直接,如果有值则返回该值,否则返回传递给它的参数值。如下示例代码,如果name为null则返回"Sim",如果name不为空则直接返回name。

@TestpublicvoidgetOptionOrElse(){
Stringname=null;
Optional<String>opt=Optional.ofNullable(name);
StringnameStr=opt.orElse("Sim");
System.out.println(nameStr);
    }

2.orElseGet()

此方法略有不同。这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果:

@TestpublicvoidgetOptionOrElseGet(){
Useruser=null;
Useruser2=newUser();
user2.setName("abc");
Useruser3=Optional.ofNullable(user).orElseGet(
                () ->user2);
System.out.println(user3);
    }

3.orElse和orElseGet区别

当Optional中对象为空是,两者没有区别都,返回默认值或供给函数提供的值。

当Optional中对象不为空,orElse仍然执行产生默认值的方法,如下图所示:

image.png

当Optional中对象不为空,orElseGet不会执行产生默认值的方法,如下图所示:

image.png

五、返回异常

1.orElseThrow()

当Optional对象值为空的时抛出异常,异常可以自定义。

@TestpublicvoidgetOptionOrElseThrow(){
Useruser2=null;
//当user2为空时,抛出异常Useruser3=Optional.ofNullable(user2).orElseThrow(
                () ->newIllegalArgumentException() );
    }

六、转换值

1.map方法

map方法接收一个function接口,并且把返回值包装成Optional对象,使对返回值进行链式调用的操作成为可能,如下代码所示,调用map后,可紧着调用orElse

@TestpublicvoidtestMap(){
Useruser2=newUser();
user2.setName("Lisa");
user2.setAddress("上海");
Stringaddress=Optional.ofNullable(user2).
map(u->u.getAddress()).orElse("北京");
System.out.println(address);
    }

2.flatMap

map方法接收一个function接口,返回值直接是一个Optional对象,不需要进行重新包装。

publicOptional<String>getCode(){
returnOptional.ofNullable(code);
    } 
@TestpublicvoidtestFlatMap(){
Useruser2=newUser();
user2.setName("Lisa");
user2.setAddress("上海");
Stringcode=Optional.ofNullable(user2).flatMap(u->u.getCode()).orElse("北京");
System.out.println(code);
    }

七、过滤值

Optional  类也提供了按条件“过滤”值的方法,filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。

@TestpublicvoidtestFilter() {
Useruser=newUser();
user.setEmail("anna@gmail.com");
Optional<User>result=Optional.ofNullable(user)
                .filter(u->StringUtils.isNotEmpty(u.getEmail()) &&u.getEmail().contains("@"));
System.out.println(result);
    }

八、怎么使用Optional

1.使用场景

Optional 主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。

Optional 类有一个非常有用的用例,就是将其与流或其它返回 Optional 的方法结合,以构建流畅的API。

2.不适合使用场景

Optional 不是 Serializable。因此,它不应该用作类的字段。如果你需要序列化的对象包含 Optional 值,Jackson 库支持把 Optional 当作普通对象。也就是说,Jackson 会把空对象看作 null,而有值的对象则把其值看作对应域的值。这个功能在 jackson-modules-java8 项目中。

它在另一种情况下也并不怎么有用,就是在将其类型用作方法或构建方法的参数时,这样做会让代码变得复杂,完全没有必要。比如以下代码

Useruser=newUser(23, "Lisa", Optional.empty());

九、总结

Optional主要用来解决空指针异常,结合Stream流及Lambda表达式,使应用程序更加优化及健壮。


相关文章
|
3月前
|
编解码 Oracle Java
java9到java17的新特性学习--github新项目
本文宣布了一个名为"JavaLearnNote"的新GitHub项目,该项目旨在帮助Java开发者深入理解和掌握从Java 9到Java 17的每个版本的关键新特性,并通过实战演示、社区支持和持续更新来促进学习。
101 3
|
3月前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
109 43
Java学习十六—掌握注解:让编程更简单
|
2月前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
3月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
47 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
2月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
3月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
62 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
3月前
|
前端开发 Java 应用服务中间件
Javaweb学习
【10月更文挑战第1天】Javaweb学习
41 2
|
3月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
31 3
|
3月前
|
存储 安全 Java
【用Java学习数据结构系列】探索栈和队列的无尽秘密
【用Java学习数据结构系列】探索栈和队列的无尽秘密
40 2
|
3月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
26 2