Java8中Optional操作的实际应用

目录
  • 简介
  • 正文
    • 1. Optional是什么
    • 2. 没它 VS 有它
    • 3. 核心操作
  • 4. 应用
  • 总结
  • 总结

简介

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

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

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

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

正文

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;

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

  • 没有用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);
}
  • 有用Optional进行包裹的参数:比如数据库查询时,我们可以用Optional来包裹查询的结果并返回,这样我们分析结果的时候,只需要通过orElse()来获取,同时还可以设定默认值
// 返回Optional<Car>,通过.orElse(defaultCar)就可以获取返回值,如果返回值为null,还可以设定一个默认值defaultCar
Optional<Car> selectOne(SelectStatementProvider selectStatement);

总结

  • Optional是什么:一个容器,存放一个对象,对象可以为null
  • 没它 VS 有它:看场景
    • 如果只是单个的if/else判断,那就没它会好点;
    • 如果嵌套比较多,或者本来传来的数据就是Optional类型,那肯定是Optional合适
  • 核心操作:不常用的这里就不写了
    • 保存数据:工厂方法 of()ofNullable()
    • 处理数据:map(), filter(), flatMap()
    • 获取数据:orElse()
  • 应用:主要用在非空判断,实际场景的话,我们可以用在数据库查询语句中

总结

到此这篇关于Java8中Optional操作的文章就介绍到这了,更多相关Java8中Optional操作内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java8新特性之Optional的深入解析

    前言 最近脑袋发热追着java8源码看的很起劲,还有了执念,罪过. 本文以jdk1.8.0_111源码为例 public final class Optional<T> {} Optional是一个为了解决NullPointerException设计而生可以包含对象也可以包含空的容器对象.封装了很多对空处理的方法也增加了filter.map这样的检索利器,其中函数式编程会有种炫酷到爆的感觉. 基础测试用例对象: public class Java8OptionalTest { List<

  • java8中forkjoin和optional框架使用

    并行流与串行流 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API 可以声明性地通过 parallel()与 sequential()在并行流与顺序流之间进行切换. 了解 Fork/Join 框架 Fork/Join 框架:就是在必要的情况下,将一个大任务,进形拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运行的结果进行join汇总. Fork/Join 框架

  • 使用Java8中Optional机制的正确姿势

    前言 Java8带来的函数式编程特性对于习惯命令式编程的程序员来说还是有一定的障碍的,我们只有深入了解这些机制的方方面面才能运用自如.Null的处理在JAVA编程中是出了try catch之外的另一个头疼的问题,需要大量的非空判断模板代码,程序逻辑嵌套层次太深.尤其是对集合的使用,需要层层判空. 首先来看下Optional类的结构图: 而如果我们对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了 Optional<User

  • Java8中Optional的一些常见错误用法总结

    前言 Java 8 引入的 Optional 类型,基本是把它当作 null 值优雅的处理方式.其实也不完全如此,Optional 在语义上更能体现有还是没有值.所以它不是设计来作为 null 的替代品,如果方法返回 null 值表达了二义性,没有结果或是执行中出现异常. 在 Oracle  做  Java 语言工作的  Brian Goetz 在 Stack Overflow 回复 Should Java 8 getters return optional type? 中讲述了引入  Opti

  • Java8 Optional判空详解(简化判空操作)

    一.导语 在没有用Optional判空之前,你是否也像下面的代码一样判空呢?如果是,请往下看,Optional 相对传统判空的优势. 传统阶层判空 为什么要用Optional,它到底是什么东西 你也看到了上面的那张图,一旦代码量大起来了,条件多了,代码就会变得很冗余,变得难以维护.那么此时我们就有必要了解Optional了. Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象.Optional 是个容器:它可以

  • Java8 Optional的详细使用教程

    Optional介绍 Optional是Jdk1.8提供的一个新类,希望可以通过该类的引入解决令人烦躁的null判断问题,非常好用.个人理解:这个类是一个包装类,将要操作的java bean封装到该类的对象里面,同时将一些常用的判断逻辑封装为成员方法,结合lambda语法,实现比较优雅的链式调用.现在对Optional的API使用做一个简单的说明. API介绍 Optional的所有的方法如下图所示,这些API大致可以分为以下几类: 1.构建API:构建一个Optional对象:方法有:empt

  • Java8 Optional优雅空值判断的示例代码

    先介绍一下API,与其他文章不同的是,本文采取类比的方式来讲,同时结合源码.而不像其他文章一样,一个个API罗列出来,让人找不到重点. 1.Optional(T value),empty(),of(T value),ofNullable(T value) 这四个函数之间具有相关性,因此放在一组进行记忆. 先说明一下,Optional(T value),即构造函数,它是private权限的,不能由外部调用的.其余三个函数是public权限,供我们所调用.那么,Optional的本质,就是内部储存了

  • JAVA8如何妙用Optional解决NPE问题详解

    引言 NPE(NullPointerException)是调试程序最常见的异常.google一下有很多关于方法到底应该返回null还是new一个空对象的讨论. 在文章的开头,先说下NPE问题,NPE问题就是,我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示 在这种情况下,有如下代码 user.getAddress().getProvince(); 这种写法,在user为null时,是有可能报NullPointerException异常的

  • Java8 Optional原理及用法解析

    平时开发的工作中, 自己组内的很多大佬经常使用Optional的用法, 自己问他们, 这个到底有什么好处呢,他们说可以很好的规避好空指针的问题, 我们在平时写java代码的时候, 如果是一个新手, 肯定很多情况下都会出现空指针的报错, 而java8 以后提供的Optional的问题, 就可以很好地规避我们空指针的问题. 空指针异常是导致Java应用程序失败的最常见原因.以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代

  • 利用Java8 Optional如何避免空指针异常详解

    前言 空指针是我们最常见也最讨厌的异常,为了防止空指针异常,你不得在代码里写大量的非空判断. Java 8引入了一个新的Optional类.用于避免空指针的出现,也无需在写大量的if(obj!=null)这样的判断了,前提是你得将数据用Optional装着,它就是一个包裹着对象的容器. 都说没有遇到过空指针异常的程序员不是Java程序员,null确实引发过很多问题.Java 8中引入了一个叫做java.util.Optional的新类可以避免null引起的诸多问题. 我们看看一个null引用能导

随机推荐