Java 8(六):Optional 空值(NULL)处理

文章目录

    • 1、简介
    • 2、什么是null类型
    • 3、只返回null有什么问题?
    • 4、Java 8 Optionals 如何提供解决方案?
      • 4.1、创建 Optional 对象
        • 4.1.1、Optional.empty()
        • 4.1.2、Optional.of()
        • 4.1.3、Optional.ofNullable()
      • 4.2、默认/缺省值和操作
      • 4.3、使用过滤方法(filter)排除某些值
    • 5、Optional 内部是如何工作的
    • 6、Optional 的方法
    • 7、Optional 试图解决的问题
    • 8、Optional 不能解决的问题
    • 9、Optional 应该在何处使用

1、简介

首先,Optional 它不是一个函数式接口,设计它的目的是为了防止空指针异常(NullPointerException),要知道在 Java 编程中,
空指针异常可是臭名昭著的。

你可以将 Optional 看做是包装对象(可能是 null, 也有可能非 null)的容器。当你定义了
一个方法,这个方法返回的对象可能是空,也有可能非空的时候,你就可以考虑用 Optional 来包装它,这也是在 Java 8 被推荐使用的做法。

2、什么是null类型

在Java中,我们使用引用类型来获取对象的访问权限,当我们没有特定的对象来使我们的引用指向时,我们将这样的引用设置为null意味着没有值。

null的使用是如此常见,以至于我们很少考虑它。 例如,对象的字段成员会自动初始化为null,并且程序员通常会在没有初始值的情况下将引用类型初始化为null。

3、只返回null有什么问题?

NullPointerException 是目前Java程序开发中最典型的异常。它会使你的代码膨胀,它让你的代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶。它自身是毫无意义的,null自身没有任何的语义

null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题,原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个null变量最初的赋值到底是什么类型。

那么,应该如何处理这个问题呢?我们就带着这个疑问,在 java 8 Optionals 里寻找一下答案。

4、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可能为空的情况。

4.1、创建 Optional 对象

4.1.1、Optional.empty()

通过静态工厂方法Optional.empty(),创建一个空的Optional对象

Optional possible = Optional.empty();

4.1.2、Optional.of()

使用静态工厂方法Optional.of(),依据一个非空值创建一个Optional对象。如果在()中传递null,则会立即抛出NullPointerException。

Optional possible = Optional.of(5);

4.1.3、Optional.ofNullable()

使用静态工厂方法 Optional.ofNullable(),你可以创建一个允许null值的Optional对象。如果参数为null,则生成的Optional对象将为空。

Optional possible = Optional.ofNullable(null);
//or
Optional possible = Optional.ofNullable(5);

4.2、默认/缺省值和操作

编程中的典型模式是,如果确定操作的结果为空,则返回默认值。 通常,您可以使用三元运算符, 但是使用Optionals,您可以编写如下代码:

//假设此值已从方法返回
Optional companyOptional = Optional.empty();
 
//如果值存在然后返回,否则创建一个新对象并返回
Company company = companyOptional.orElse(new Company());
 
//或者您也可以抛出异常
Company company = companyOptional.orElseThrow(IllegalStateException::new);

4.3、使用过滤方法(filter)排除某些值

通常,您需要在对象上调用方法并检查某些属性。 例如 在下面的示例代码中检查公司是否有“财务”部门, 如果有,则打印出来。

Optional companyOptional = Optional.empty();
companyOptional.filter(department -> "Finance".equals(department.getName())
                    .ifPresent(() -> System.out.println("Finance is present"));

filter方法将谓词作为参数。 如果Optional对象中存在一个值并且它与谓词匹配,则filter方法返回该值; 否则,它返回一个空的Optional对象。

5、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;
}

6、Optional 的方法

序号 方法 & 描述
1 static Optional empty()

返回空的 Optional 实例。

2 boolean equals(Object obj)

判断其他对象是否等于 Optional。

3 Optional filter(Predicate predicate)

如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。

4 Optional flatMap(Function> mapper)

如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional

5 T get()

如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException

6 int hashCode()

返回存在值的哈希码,如果值不存在 返回 0。

7 void ifPresent(Consumer consumer)

如果值存在则使用该值调用 consumer , 否则不做任何事情。

8 boolean isPresent()

如果值存在则方法会返回true,否则返回 false。

9 Optional map(Function mapper)

如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。

10 static Optional of(T value)

返回一个指定非null值的Optional。

11 static Optional ofNullable(T value)

如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。

12 T orElse(T other)

如果存在该值,返回值, 否则返回 other。

13 T orElseGet(Supplier other)

如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。

14 T orElseThrow(Supplier exceptionSupplier)

如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常

15 String toString()

返回一个Optional的非空字符串,用来调试

7、Optional 试图解决的问题

Optional 是尝试通过添加更有效的API 来减少Java系统中的空指针异常的数量,它会考虑到有时缺少返回值。 如果从一开始就有 Optional,那么今天大多数库和应用程序可能会更好地处理缺少的返回值,减少或避免空指针异常。

通过使用 Optional,用户被迫考虑 null或缺省值的情况,除了通过赋予null之外,Optional的最大优点是它会强制您主动考虑缺省值情况,否则无法编译通过。

8、Optional 不能解决的问题

Optional 并不意味着是一种避免所有类型的空指针的机制。在使用 Optional 的时候需要考虑一些事情,以决定什么时候怎样使用它。重要的一点是 Optional 不是 Serializable。因此,它不应该用作类的字段。

请注意,Optional 不适用于以下这些情况:

  1. 在域模型层(domain model layer)(它不可序列化)
  2. 在DTO中(它不可序列化)
  3. 在方法的输入参数中
  4. 在构造函数参数中

9、Optional 应该在何处使用

Optional 主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。

参考文档:

https://howtodoinjava.com/java8/java-8-optionals-complete-reference/

你可能感兴趣的:(【基础】Java基础,Java,8,新特性专栏,java,8,optional)