作者:汤圆

个人博客:javalover.cc

前言

官人们好啊,我是汤圆,今天给大家带来的是《Java8中的Optional操作》,希望有所帮助,谢谢

文章纯属原创,个人总结难免有差错,如果有,麻烦在评论区回复或后台私信,谢啦

最近看到有几个粉丝了(窃喜),多的话我也不说了,欢迎加入我们的荣华富贵大家庭

简介

目的:Optional的出现主要是为了解决null指针问题,也叫NPE(NullPointerException)

外形:Optional外形酷似容器(其实它就是一个容器),只是这个容器比较特殊,因为它只能存放一个对象,运气不好的话这个对象还是个null

操作:Optional从操作上来看,又跟前面的Stream流式操作很像,比如过滤filter - 提取map等

下面我们用比较简单的例子来对比着看下,Optional的一些基础用法

先来看下目录

目录

  1. Optional是什么

  2. 没它 VS 有它

  3. 核心操作

  4. 应用

正文

1. Optional是什么

Optional是一个容器,只能存放一个对象(可为null)

Optional的出现是

  • 一个是为了解决NPE问题(阿里开发手册也有提到这一点,点击可直接下载,官方链接)
  • 另一个是为了代码更加清晰可读,因为Optional这个名字的灵感就是来自英文optional(可选的),意思就是说这个对象可以为空,可以不为空

2. 没它 VS 有它

下面我们用旧代码和新代码来对比着看(所谓的新旧是以Java8为分割线)

案例1:现有C类,我们要提取C.name属性

public class OptionalDemo {
private static final String DEFAULT_NAME = "javalover"; public static void main(String[] args) {
// 传入null,以身试法
getName(null);
}
// 取出c.name
public static void getName(C c){
// 旧代码 Java8之前
String name = (c!=null ? c.getName() : DEFAULT_NAME);
System.out.println("old: "+name);
// 新代码 Java8之后(下面的三个操作方法后面会介绍,这里简单了解下)
String nameNew = Optional
// 工厂方法,创建Optional<C>对象,如果c为null,则创建空的Optional<C>对象
.ofNullable(c)
// 提取name,这里要注意,即使c==null,这里也不会抛出NPE,而是返回空的Optional<String>,所以在处理数据时,我们不需要担心空指针异常
.map(c1->c1.getName())
// 获取optional的属性值,如果为null,则返回给定的实参DEFAULT_NAME
.orElse(DEFAULT_NAME); System.out.println("new: "+nameNew);
}
}
class C{
private String name; public C(String name) {
this.name = name;
}
// 省略getter/setter
}

乍一看,好像Java8之前的旧代码更合适啊,只需要一个三目运算符

再看Optional操作,发现并没有那么简洁

是这样的,如果只是一层判断,那普通的if判断做起来更方便;

但是如果嵌套两层呢,比如b.getC().getName()?

下面我们就看下,两层嵌套会怎么样

例子2:现多了一个B类(依赖C类),我们要从对象B中提取C的属性name,即b.getC().getName()

public static void getName2(B b){
// 旧代码
String name = (b!=null ? ( b.getC()!=null ? b.getC().getName() : DEFAULT_NAME) : DEFAULT_NAME);
// 新代码
String nameNew = Optional
.ofNullable(b)
.map(b1->b1.getC())
.map(c1->c1.getName())
.orElse(DEFAULT_NAME);
System.out.println(nameNew);
} class B{
private C c; public B(C c) {
this.c = c;
}
// 省略getter/setter
}

这次不管是乍一看,还是一直看,都是Optional更胜一筹

例子3:现多了一个A类(依赖B类),我们要提取a.getB().getC().getName()

等等等,省略号

意思到就行,反正要说的就是单从判空来看的话,Optional肯定是好过三目运算符的(if/else这里就不举了,它的嵌套只会更多)

3. 核心操作

因为Optional主要是操作数据(类似数据库操作),所以我们这里从数据的角度来进行分析

这里我们可以分为三种操作:保存数据、处理数据、获取数据

保存数据

  • (没有默认值)public static <T> Optional<T> of(T value) :填充 T value 到 Optional 的属性中;如果 value==null,则抛出NPE
  • (默认null)public static <T> Optional<T> ofNullable(T value) :填充 T value 到 Optional 的属性中;如果引用为null,则填充null
  • (构造一个空的Optional)public static<T> Optional<T> empty():单纯地创建一个数据为null的空Optional,即直接填充null到 Optional 的属性中【不常用】

处理数据

  • (提取)public<U> Optional<U> map(Function<? super T, ? extends U> mapper) :提取Optional中属性T的某个属性值U,并将U填充到新的Optional中并返回
  • (过滤)public Optional<T> filter(Predicate<? super T> predicate) :过滤Optional中属性T的某个属性值,符合条件则将T填充到新的Optional中并返回
  • (扁平化提取)public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):提取Optional中属性T的某个属性Optional<U>,直接返回

获取数据

  • public T orElse(T other) :获取数据,如果数据为null,则返回T other
  • public T orElseGet(Supplier<? extends T> other):获取数据,如果数据为null,则通过函数式接口other返回一个新的数据T
  • public T get() :获取数据,如果数据为null,则报NPE【不常用】

上面这些操作中,不常用的就是get()和empty()

其他的就不举了,这里主要说下map()和flatMap()

如下图所示:

map()主要是提取Optional中的属性C的属性name,然后再包装到新的Optional

输入Optional<C>, 输出Optional<String>(即Optional<c.name>)

String nameNew = Optional
.ofNullable(c)
.map(c1->c1.getName())
.orElse("xxx");

flatMap()主要是提取Optional中的属性B的Optional<C>属性中的C的值,然后再包装到新的Optional

输入Optional<B>,输出Optional<C>

public class FlatMapDemo {
private static final String DEFAULT_NAME = "javalover"; public static void main(String[] args) {
getName(null);
} // 取出 b.c.name
public static void getName(B b){
C c = Optional
.ofNullable(b)
// 这里扁平化处理,提取Optional<C>中的C
// 如果用map,则返回的是Optional<Optional<C>>
.flatMap(b->b.getC())
.orElse(new C("xxx"));
System.out.println(c.getName());
}
} class B{
private Optional<C> c; public Optional<C> getC() {
return c;
} public void setC(C c) {
this.c = Optional.ofNullable(c);
}
} class C{
private String name; public C(String name) {
this.name = name;
}
// 省略getter/setter
}

4. 应用

从规范角度来讲,是为了代码清晰,一看用Optional<T>变量,就知道T可能为null;

从编码角度来讲,主要是应用在非空判断;但是实际场景的话,有两个

  1. 没有用Optional进行包裹的参数:比如上面讲到的例子,传来的参数就是普通对象,我们就需要自己用Optional容器来包裹传来的参数,然后进行后续操作
// 取出c.name
public static void getName(C c){
// 自己手动包装 Optional<C>
String nameNew = Optional
.ofNullable(c)
.map(c1->c1.getName())
.orElse(DEFAULT_NAME); System.out.println("new: "+nameNew);
}
  1. 有用Optional进行包裹的参数:比如数据库查询时,我们可以用Optional来包裹查询的结果并返回,这样我们分析结果的时候,只需要通过orElse()来获取,同时还可以设定默认值
// 返回Optional<Car>,通过.orElse(defaultCar)就可以获取返回值,如果返回值为null,还可以设定一个默认值defaultCar
Optional<Car> selectOne(SelectStatementProvider selectStatement);

总结

  1. Optional是什么:一个容器,存放一个对象,对象可以为null

  2. 没它 VS 有它:看场景

    • 如果只是单个的if/else判断,那就没它会好点;

    • 如果嵌套比较多,或者本来传来的数据就是Optional类型,那肯定是Optional合适

  3. 核心操作:不常用的这里就不写了

    • 保存数据:工厂方法 of()ofNullable()
    • 处理数据:map(), filter(), flatMap()
    • 获取数据:orElse()
  4. 应用:主要用在非空判断,实际场景的话,我们可以用在数据库查询语句中

后记

最后,感谢大家的观看,谢谢

原创不易,期待官人们的三连哟

Java8中的Optional操作的更多相关文章

  1. Java8中的流操作-基本使用&性能测试

    为获得更好的阅读体验,请访问原文:传送门 一.流(Stream)简介 流是 Java8 中 API 的新成员,它允许你以声明式的方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现).这有点儿 ...

  2. java8中的流操作

    https://www.ibm.com/developerworks/cn/java/j-experience-stream/index.html Stream 流是 Java 8 新提供给开发者的一 ...

  3. java8中的Optional

    Optional类主要解决空指针异常NullPointerException.Optional 类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用 null 表示一 ...

  4. Java8 中的 Optional

    从 Java 8 引入的一个很有趣的特性是 Optional  类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都 ...

  5. Java8 中的 Optional 相关用法

    基本方法: ofNullable() 为可能 null 的值创建一个 Optional 实例,  然后可以对该实例遍历/过滤, 判断是否存在,或者为空时执行.. ifPresent(...) 如果值存 ...

  6. 使用Java8中的Optional类来消除代码中的null检查

    简介 Optional类是Java 8新增的一个类,Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException). —— 每个 Java 程序员都非常了解的异常 ...

  7. 一篇文章教会你使用Java8中的Lambda表达式

    简介 Java 8为开发者带来了许多重量级的新特性,包括Lambda表达式,流式数据处理,新的Optional类,新的日期和时间API等.这些新特性给Java开发者带来了福音,特别是Lambda表达式 ...

  8. Java8中的Stream API

    本篇文章继续介绍Java 8的另一个新特性——Stream API.新增的Stream API与InputStream和OutputStream是完全不同的概念,Stream API是对Java中集合 ...

  9. Java8 新特性 Optional 类

    Optional 类的简介   Optional类的是来自谷歌Guava的启发,然后就加入到Java8新特性中去了.Optional类主要就是为子决解价值亿万的错误,空指针异常.   Optional ...

随机推荐

  1. 系统错误,MSVCP100D.dll找不到或丢失!

    文章首发 | 公众号:lunvey 今日研究c++,找了一些示例程序,发现无法打开.弹出如下的报错提示: 作为新时代人类,遇见问题第一件事情就是问度娘.然而眼花缭乱的检索数据,大家众说纷纭,不知道如何 ...

  2. TERSUS无代码开发(笔记06)-简单实例手机端页面设计

    手机端的设计 1.页面说明 2.默认页面===>提交请假单(上面页面双击进入,页面主要编辑区) 2.1默认页面===>提交请假单===>头部区(页面部份主要编辑区01) 2.1.1默 ...

  3. Vue框架-组件的概念及使用

    目录 一.Vue组件 1. 组件分类 1.1 根组件 1.2 局部组件 1.3 全局组件 2. 组件的特点 3. 如何创建组件 4. 组件的数据局部化 5. 组件传参·父传子 6. 组件传参·子传父 ...

  4. 设置ViewPager 自动滑动时间,速度 方便展示动画

    ViewPager.setCurrentItem(position),即使已设置动画,但是没有动画效果 原因:因为ViewPager滑动之前的时间间隔太短,可以通过反射,去修改ViewPager自动滑 ...

  5. Kubernetes-3.安装

    docker version:19.03.14 kubernetes version:1.19.4 本文介绍使用kubeadm安装Kubernetes集群的简单过程. 目录 使用kubeadm安装k8 ...

  6. python基础学习之类的继承、魔法方法

    什么是继承 即类A可以使用类B的方法,即B是A的父类,A是B的子类,AB之间是继承关系 class Father():  # 父类 def __init__(self,name,age): self. ...

  7. javascript 之对象-13

    对象 无序属性的集合,属性可以包含基本值.对象或者函数,简单理解为对象是若干属性的集合:我们常说的面向对象(oop)编程其实是指的一种编码的思想,简单理解为用对象来封装数据,利用封装.继承.多态对代码 ...

  8. mysql中的基础查询 练习

    #进阶1:基础查询 /* 语法: select 查询列表 from 表名; 类似于:System.out.println(打印东西); 特点: 1.查询列表可以是:表中的字段.常量值.表达式.函数 2 ...

  9. Java 8的这些新特性,不一样的全新版本(万字长文详细说明)

    目录 1.Lambda表达式 2.Stream API 2.1 入门介绍 2.2.什么是Stream流 2.3.Stream的创建 ①.通过Collection接口获取 ②.由数组创建流 ③.由值创建 ...

  10. ELK(ElasticSearch+Logstash+Kibana)配置中的一些坑基于7.6版本

    三个组件都是采用Docker镜像安装,过程简单不做赘述,直接使用Docker官方镜像运行容器即可,注意三个组件版本必须一致. 运行容器时最好将三个组件的核心配置文件与主机做映射,方便直接在主机修改不用 ...