首先,Optional 它不是一个函数式接口,设计它的目的是为了防止空指针异常(NullPointerException),要知道在 Java 编程中,
空指针异常可是臭名昭著的。
你可以将 Optional 看做是包装对象(可能是 null, 也有可能非 null)的容器。当你定义了
一个方法,这个方法返回的对象可能是空,也有可能非空的时候,你就可以考虑用 Optional 来包装它,这也是在 Java 8 被推荐使用的做法。
在Java中,我们使用引用类型来获取对象的访问权限,当我们没有特定的对象来使我们的引用指向时,我们将这样的引用设置为null意味着没有值。
null的使用是如此常见,以至于我们很少考虑它。 例如,对象的字段成员会自动初始化为null,并且程序员通常会在没有初始值的情况下将引用类型初始化为null。
NullPointerException 是目前Java程序开发中最典型的异常。它会使你的代码膨胀,它让你的代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶。它自身是毫无意义的,null自身没有任何的语义
null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题,原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个null变量最初的赋值到底是什么类型。
那么,应该如何处理这个问题呢?我们就带着这个疑问,在 java 8 Optionals 里寻找一下答案。
为了更好的解决和避免NPE异常,Java 8中引入了一个新的类 java.util.Optional。这是一个封装 Optional 值的类。
变量存在时,Optional 类只是对类简单封装。变量不存在时,缺失的值会被建模成一个“空”的 Optional 对象,由方法 Optional.empty() 返回。Optional.empty() 方法是一个静态工厂方法,它返回 Optional 类的特定单一实例。
public static void main(String[] args) {
Optional canBeEmpty1 = Optional.of(5);
canBeEmpty1.isPresent(); // returns true
canBeEmpty1.get(); // returns 5
Optional canBeEmpty2 = Optional.empty();
canBeEmpty2.isPresent(); // returns false
}
您还可以将Optional视为包含值或不包含值的单值容器。
值得注意的是,Optional 类的意图不是替换每个空引用。 相反,它的目的是帮助设计更易于理解的API,这样只需读取方法的签名,就可以判断出是否可以获得可选值。 这会强制您从Optional中获取值并对其进行处理,同时处理Optional可能为空的情况。
通过静态工厂方法Optional.empty(),创建一个空的Optional对象
Optional possible = Optional.empty();
使用静态工厂方法Optional.of(),依据一个非空值创建一个Optional对象。如果在()中传递null,则会立即抛出NullPointerException。
Optional possible = Optional.of(5);
使用静态工厂方法 Optional.ofNullable(),你可以创建一个允许null值的Optional对象。如果参数为null,则生成的Optional对象将为空。
Optional possible = Optional.ofNullable(null);
//or
Optional possible = Optional.ofNullable(5);
编程中的典型模式是,如果确定操作的结果为空,则返回默认值。 通常,您可以使用三元运算符, 但是使用Optionals,您可以编写如下代码:
//假设此值已从方法返回
Optional companyOptional = Optional.empty();
//如果值存在然后返回,否则创建一个新对象并返回
Company company = companyOptional.orElse(new Company());
//或者您也可以抛出异常
Company company = companyOptional.orElseThrow(IllegalStateException::new);
通常,您需要在对象上调用方法并检查某些属性。 例如 在下面的示例代码中检查公司是否有“财务”部门, 如果有,则打印出来。
Optional companyOptional = Optional.empty();
companyOptional.filter(department -> "Finance".equals(department.getName())
.ifPresent(() -> System.out.println("Finance is present"));
filter方法将谓词作为参数。 如果Optional对象中存在一个值并且它与谓词匹配,则filter方法返回该值; 否则,它返回一个空的Optional对象。
如果打开Optional.java的源代码,您会发现 Optional 的值是这样定义的:
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
如果您定义一个空的Optional,则声明如下。 static关键字确保每个VM通常只存在一个空实例。
/**
* Common instance for {@code empty()}.
*/
private static final Optional> EMPTY = new Optional<>();
默认的构造函数是 private,因此除了上面给出的3种方法之外,你不能创建Optional的实例。
当您创建一个Optional时,下面的调用将在结束时发生,并将传递的值分配给’value’属性。
this.value = Objects.requireNonNull(value);
当您尝试从Optional获取值时,如果当前值为null,则会抛出异常 NoSuchElementException
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
序号 | 方法 & 描述 |
---|---|
1 | static 返回空的 Optional 实例。 |
2 | boolean equals(Object obj) 判断其他对象是否等于 Optional。 |
3 | Optional 如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。 |
4 | Optional flatMap(Function super T,Optional> mapper) 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional |
5 | T get() 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException |
6 | int hashCode() 返回存在值的哈希码,如果值不存在 返回 0。 |
7 | void ifPresent(Consumer super T> consumer) 如果值存在则使用该值调用 consumer , 否则不做任何事情。 |
8 | boolean isPresent() 如果值存在则方法会返回true,否则返回 false。 |
9 | Optional map(Function super T,? extends U> mapper) 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。 |
10 | static 返回一个指定非null值的Optional。 |
11 | static 如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。 |
12 | T orElse(T other) 如果存在该值,返回值, 否则返回 other。 |
13 | T orElseGet(Supplier extends T> other) 如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。 |
14 | 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常 |
15 | String toString() 返回一个Optional的非空字符串,用来调试 |
Optional 是尝试通过添加更有效的API 来减少Java系统中的空指针异常的数量,它会考虑到有时缺少返回值。 如果从一开始就有 Optional,那么今天大多数库和应用程序可能会更好地处理缺少的返回值,减少或避免空指针异常。
通过使用 Optional,用户被迫考虑 null或缺省值的情况,除了通过赋予null之外,Optional的最大优点是它会强制您主动考虑缺省值情况,否则无法编译通过。
Optional 并不意味着是一种避免所有类型的空指针的机制。在使用 Optional 的时候需要考虑一些事情,以决定什么时候怎样使用它。重要的一点是 Optional 不是 Serializable。因此,它不应该用作类的字段。
请注意,Optional 不适用于以下这些情况:
Optional 主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。
参考文档:
https://howtodoinjava.com/java8/java-8-optionals-complete-reference/