conanan's blog conanan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • Java
  • Java Web
  • 工具

    • Maven
  • MySQL
  • Redis
  • Git
  • Vim
  • Nginx
  • Docker
GitHub

Evan Xu

前端界的小学生
首页
关于
  • 分类
  • 标签
  • 归档
  • Java
  • Java Web
  • 工具

    • Maven
  • MySQL
  • Redis
  • Git
  • Vim
  • Nginx
  • Docker
GitHub
  • 基础

  • API

    • 4 API-1 字符串
    • 4 API-2 时间
    • 4 API-3 时间-old
    • 4 API-4 比较器
    • 4 API-5 精确数据类型
    • 4 API-6 Math
    • 4 API-7 Random
    • 4 API-8 System
    • 4 API-9 Object
    • 4 API-习题
    • 13 Lambda
    • 14 Stream API
    • 15 Optional
      • 简介
      • 使用
        • 创建
        • 判断、Consumer
        • 获取、Supplier
      • 示例
        • 示例 1
  • Container

  • 多线程

  • 16 9,10,11新特性
  • 17 Test
  • 18 设计原则&设计模式
  • JDBC
  • Java
  • API
conanan
2020-12-14

15 Optional

# Optional

# 简介

到目前为止,臭名昭著的空指针异常是导致 Java 应用程序失败的最常见原因。 以前,为了解决空指针异常,Google 公司著名的 Guava 项目引入了Optional类, Guava 通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代 码。受到 Google Guava 的启发,Optional类已经成为 Java 8 类库的一部分。

java.util.Optional<T> 是一个容器类,它可以保存类型 T 的值,代表这个值存在;或者仅仅保存 null,表示这个值不存在。原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。

Optional类的 Javadoc 描述如下:这是一个可以为null的容器对象。如果值存在 则isPresent()方法会返回true,调用get()方法会返回该对象。

# 使用

# 创建

创建Optional类对象的方法

  • Optional.of(T t)

    创建一个 Optional 实例,t必须非空;

  • Optional.ofNullable(T t)

    t可以为null

  • Optional.empty()

    创建一个空的 Optional 实例

# 判断、Consumer

判断Optional容器中是否包含对象

  • boolean isPresent()

    判断是否包含对象。不推荐这样用!和 if else 没区别!

  • void ifPresent(Consumer<? super T> consumer) 🔥

    如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传给它,消费掉。

# 获取、Supplier

获取Optional容器的对象

  • T get()

    如果调用对象包含值,返回该值,否则抛异常。注意,这里直接使用 get IDEA 会有黄色警告,因为这样就和普通用法一样了,失去 Optional 存在的意义。且注意,这里 get 后若没有值,则直接抛异常,将可能产生的 NPE 提前(类似 fast fail 机制;泛型的提前到编译期;)

    这个方法封装的很有用,但是一般推荐下面的用法

  • T orElse(T other) 🔥

    如果有值则将其返回,否则直接返回指定的 other 对象。

  • T orElseGet(Supplier<? extends T> other) 🔥

    如果有值则将其返回,否则返回由Supplier接口实现提供的对象。

  • T orElseThrow(Supplier<? extends X> exceptionSupplier) 🔥

    如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。

# 示例

# 示例 1

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Girl {
    private String name;
}
1
2
3
4
5
6
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Boy {

    private Girl girl;
}
1
2
3
4
5
6
7
@Test
void test1() {
    // 可能是其他地方传来的值,不确定其是否为null
    Girl girl = null;

    //of(T t):保证t是非空的,对于 null 执行会报 NPE
    // Optional<Girl> optionalGirl1 = Optional.of(girl);

    //ofNullable(T t):t可以为null,执行输出为Optional.empty
    Optional<Girl> optionalGirl2 = Optional.ofNullable(girl);
    System.out.println(optionalGirl2);// Optional.empty


    //orElse(T t1):如果当前的Optional内部封装的t是非空的,则返回内部的t;如果内部的t是空的,则返回orElse()方法中的参数t1.
    Girl girl1 = optionalGirl2.orElse(new Girl("赵丽颖"));
    System.out.println(girl1);// Girl(name=赵丽颖)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void test2(){
    // 可能其他地方传入的值,无法确定其是否为 null
    Boy boy = new Boy();
    boy = null;

    String girlName = getGirlName(boy);
    System.out.println(girlName);

}

//优化之前的 getGirlName():
public String getGirlName(Boy boy){
    return boy.getGirl().getName();
}


//优化以后的 getGirlName():
public String getGirlName1(Boy boy){
    if(boy != null){
        Girl girl = boy.getGirl();
        if(girl != null){
            return girl.getName();
        }
    }
    return null;
}

@Test
public void test3(){
    // 分别注释如下可得结果
    Boy boy = null;// 迪丽热巴
    boy = new Boy();// 古力娜扎
    boy = new Boy(new Girl("桥本有菜"));// 桥本有菜
    String girlName = getGirlName2(boy);
    System.out.println(girlName);
}


//使用 Optional 容器后的 getGirlName():
public String getGirlName2(Boy boy){

    Optional<Boy> boyOptional = Optional.ofNullable(boy);
    // 此时的boy1一定非 null
    Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
    // 但是 girl 可能为 null
    Girl girl = boy1.getGirl();

    Optional<Girl> girlOptional = Optional.ofNullable(girl);
    // girl1一定非空
    Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
    return girl1.getName();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
编辑
上次更新: 2021/06/21, 15:45:42
14 Stream API
6 Container-1 数据结构

← 14 Stream API 6 Container-1 数据结构→

最近更新
01
线程生命周期
07-06
02
线程安全理论
06-24
03
并发简史
06-24
更多文章>
Theme by Vdoing | Copyright © 2019-2021 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×