开发使用Optional类的代码

关于 null 的问题

大多数编程语言都有一种表示没有值的数据类型,它有许多名称

NULL, nil, None, Nothing

1965年 Tony Hoare 在 ALGOL W 中引入了 null 类型,它被认为是计算机科学中最严重的错误之一

  • null 有什么问题
String summary = 
  book.getChapter(10)
          .getSummary().toUpperCase();

如果这些方法中的任何一个返回一个 null 引用(例如,如果书中没有第十章) ,那么在运行时停止程序时将抛出一个 NullPointerException(NPE)

  • 避免NPE
    检查null
String summary = "";
if(book != null) {
    Chapter chapter = book.getChapter(10);
    if(chapter != null) {
        if(chapter.getSummary() != null) {
          summary = chapter.getSummary()
                        .toUpperCase();
        }
    }
}

检查null的问题

  • 不知道结构中的任何对象是否可以为空,要检查每个对象是否有这个值。它不太实用,并且损害了可读性。
  • 检查 null 真的值得吗?如果这些对象永远不应该为空呢?通过检查 null,我们将隐藏错误并且不处理它。
  • 那么使用什么作为默认值会更好呢?空字符串还是null?

为了解决这个问题,java8引入了java.util.Optional

Optional类

这个类的为可以为null的对象封装一个可选值。

  • 如果可能为null的属性,我门可以这么设置属性
class Chapter {
    private Optional<String> summary;
    // Other attributes and methods
}

如果该属性有值,Optional 类只是包装它。否则,一个空值由 Optional.empty ()方法表示,该方法返回 Optional 的单例实例。
通过使用这个类而不是 null避免NPE,同时可以使用 Optional 的有用方法

创建Optional实例

image.png
Optional构造方法私有化

  • 一个空的Optional
Optional<String> summary = Optional.empty();

该方法的value为null

  • 确定一个对象不是 null
Optional<String> summary = Optional.of("A summary");

1.如果非null,则返回带有指定值的 Optional 实例
2.为null,返回空 Optional

  • 你想知道一个 Optional 是否包含一个值
if( summary.isPresent() ) {
    // Do something
}
  • 或者以一种更实用的方式
summary.ifPresent(s -> System.out.println(s));
// Or summary.ifPresent(System.out::println);

这个方法仅当 Optional 包含值才进行Consumer接口函数
image.png

  • 获得一个可选使用的值
String s = summary.get();

如果 Optional 不包含值,这个方法将抛出一个 java.util.NoSuchElementException 异常,因此最好使用 ifPresent ()方法
image.png

  • 如果我们想在 Optional 不包含值的情况下返回一些东西,我们可以使用其他三种方法
    1.当 Optional 为空时,orElse ()方法返回参数(必须是类型 t,在本例中是 String)
String summaryOrDefault = summary.orElse("Default summary");

image.png
2.orElseGet ()方法采用Supplier<? extends T>作为一个参数,当 Optional 为空时返回一个值。否则,它返回封装的值

String summaryOrDefault =
        summary.orElseGet( () -> "Default summary" );

image.png
3.orElseThrow ()方法Supplier<? extends X> 是当 Optional 为空时抛出的异常类型。否则,它返回封装的值。

String summaryOrException =
        summary.orElseThrow( () -> new Exception() );

image.png

其他类型的Optional

像Stream一样,Optional 类也有一些版本来处理原语,OptionalInt,OptionalLong 和 OptionalDouble,所以你可以使用 OptionalInt 来代替Optional
image.png

OptionalInt optionalInt = OptionalInt.of(1);
int i = optionalInt.getAsInt();

不鼓励使用这些原语版本,特别是因为它们缺少三种有用的方法: filter ()、 map ()和 flatMap ()。而且由于 Optional 只包含一个值,装箱/取消装箱原语的开销并不显著

filter

如果存在一个值并与给定的预测值相匹配,filter ()方法将返回 Optional。否则,返回一个空的 Optional

map

Map ()方法通常用于从一种类型转换到另一种类型。如果该值存在,使用Function< ? super T, ? extends U >转换入参。

int summaryLength = summary.map(s -> s.length()).orElse(0);

flapMap ()

但它采用的参数类型是Function<? super T, Optional>,如果值存在,它返回应用提供的函数产生的Optional。否则,它将返回一个空 Optional

总结

  • Optional类封装了一个可选值,即可以为null的对象。
  • 空值由Optional.empty()方法表示。
  • 可以使用of()方法将对象包装为可选的,但是,如果对象为null,则会引发NullPointerException。
  • 如果可选实例的值为非null,则方法ofNullable()返回一个具有指定值的可选实例。否则,它将返回一个空的可选值。
  • 要获取可选项的值,请使用get()方法,但是如果可选项不包含值,它将抛出java.util.NoSuchElementException,因此最好使用ifPresent()方法,该方法将Consumer< T>作为参数,仅当Optional包含值时才执行。
  • 当Optional为空时,orElse()方法返回参数,否则返回封装的值。
  • orElseGet()方法接受一个Supplier,该Supplier在Optional为空时返回一个值。否则,它将返回封装的值。
  • orElseThrow()方法接受一个Supplier,该Supplier在Optional为空时返回一个异常。否则,它将返回封装的值。

这个家伙很懒,啥也没有留下😋