Java8中的Optional操做

做者:汤圆java

我的博客:javalover.ccgit

前言

官人们好啊,我是汤圆,今天给你们带来的是《Java8中的Optional操做》,但愿有所帮助,谢谢github

文章纯属原创,我的总结不免有差错,若是有,麻烦在评论区回复或后台私信,谢啦

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

简介

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

外形:Optional外形酷似容器(其实它就是一个容器),只是这个容器比较特殊,由于它只能存放一个对象,运气很差的话这个对象仍是个nullide

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

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

先来看下目录编码

目录

  1. Optional是什么
  2. 没它 VS 有它
  3. 核心操做
  4. 应用

正文

1. Optional是什么

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

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()

B依赖C

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()

A依赖B

等等等,省略号

意思到就行,反正要说的就是单从判空来看的话,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>)

map

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

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

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

flatMap

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. 应用:主要用在非空判断,实际场景的话,咱们能够用在数据库查询语句中

后记

最后,感谢你们的观看,谢谢

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

相关文章
相关标签/搜索