乐趣区

关于java:Java8中的Optional操作

作者:汤圆

集体博客: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. 利用:次要用在非空判断,理论场景的话,咱们能够用在数据库查问语句中

后记

最初,感激大家的观看,谢谢

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

退出移动版