使用Optional处理null

zjun Lv4

Java 8引入了一个Optional类,用来解决空指针异常(NullPointerException)。刚开始使用的时候看到ifPresent(),isPresent()get()这些函数,感觉和直接通过比较null值的方式差别不大,纯属脱了裤子放屁。可是后来看到一些最佳实践的代码例子,才发觉是之前肤浅了,没有理解到Optional的正确的打开方式,所以在这里记录一下。

一个例子

使用Optional之前
如果一个类中嵌套了很多层的对象,那么为了访问最里层的嵌套对象,不得不写出下面这种很繁琐的代码。

1
2
3
4
5
6
7
8
9
10
11
12
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}

使用Optional后
如果使用Optional的话,只需要一行代码就可以搞定。

1
2
3
4
5
String isocode = Optional.ofNullable(user)
    .map(u -> u.getAddress())
    .map(a -> a.getCountry())
    .map(c -> c.getIsocode())
    .orElse("default");

最佳实践

Optional 是用来作为方法返回值的

Optional 是为了清晰地表达返回值中没有结果的可能性,且如果直接返回 null 很可能导致调用端产生错误(尤其是NullPointerException)。通常用来作为方法返回值,不建议用着方法参数。

1
2
// 创建一个可能为空的 Optional 对象
Optional<String> name = Optional.ofNullable("Hello");

使用orElse(),orElseGet(),orElseThrow()取值

  • T orElse(T other): 如果值存在返回,否则返回orElse中传入的other
  • T orElseGet(Supplier<? extends T> other) :如果存在则返回该值,否则调用other这个函数编程并返回该调用的结果
  • T orElseThrow(Supplier<? extends X> exceptionSupplier): 如果存在则返回该值,否则为空的话可以抛出自定义的异常
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Optional<String> name = Optional.ofNullable(null);

    // 使用 orElse(T other)
    String greeting = "Hello, " + name.orElse("Guest"); //如果 Optional 对象包含一个非空的值,返回该值,否则返回给定的默认值
    System.out.println(greeting); // 输出:Hello Guest

    // 使用 orElseGet(Supplier<? extends T> supplier)
    greeting = "Hello, " + name.orElseGet(() -> "Guset");//如果 Optional 对象包含一个非空的值,返回该值,否则返回由给定的供应者操作生成的值
    System.out.println(greeting); // 输出:Hello Guset

    // 使用 orElseThrow(Supplier<? extends X> exceptionSupplier)
    greeting = "Hello, " + name.orElseThrow(() -> new NullPointerException("null"));//如果 Optional 对象包含一个非空的值,返回该值,否则抛出由给定的异常供应者操作生成的异常

    // 抛出 java.lang.NullPointerException: null 异常

    orElseGet和orElse的区别?

    当 ofNullable() 传入参数不为空时,orElse() 方法仍然创建了 other这个 对象,而orElseGet() 方法不创建对象。在执行较密集的调用时,这个差异会对性能产生重大影响

使用map()和filter()函数做转换

  • Optional filter(Predicate<? super T> predicate): 对Optional中的value进行过滤,如果不匹配,返回空
    • Optional map(Function<? super T, ? extends U> mapper): 对Optional中的value进行转换映射为另外一个对象,如果value为空,返回empty Optional
  • Optional flatMap(Function<? super T, Optional> mapper): 接受一个返回值为Optional的映射函数参数,该返回值亦是flatMap方法的返回值若结果为空,则返回 空Optional
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Optional<String> name = Optional.ofNullable("John");

    // 使用 map(Function<? super T,? extends U> mapper)
    String greeting = "Hello, " + name.map(s -> s.toUpperCase()).get();//如果 Optional 对象包含一个非空的值,对该值应用给定的映射函数,返回一个包含映射结果的 Optional 对象,否则返回一个空的 Optional 对象
    System.out.println(greeting); // 输出:Hello JOHN

    // filter(Predicate<? super T> predicate)
    greeting = "Hello " + name.filter(s -> !s.isEmpty()).get();//如果 Optional 对象包含一个非空的值,并且该值满足给定的谓词条件,返回包含该值的 Optional 对象,否则返回一个空的 Optional 对象
    System.out.println(greeting); // 输出:Hello john

参考资料

  • 标题: 使用Optional处理null
  • 作者: zjun
  • 创建于 : 2018-08-03 23:01:12
  • 更新于 : 2023-12-01 16:54:07
  • 链接: https://zjun.site/2018/08/d239c27ca7d9.html
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论