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

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<Integer> canBeEmpty1 = Optional.of(5);
        canBeEmpty1.isPresent();                    // returns true
        canBeEmpty1.get();                          // returns 5

        Optional<Integer> canBeEmpty2 = Optional.empty();
        canBeEmpty2.isPresent();                    // returns false
    }

您还可以将Optional视为包含值或不包含值的单值容器。

值得注意的是,Optional 类的意图不是替换每个空引用。 相反,它的目的是帮助设计更易于理解的API,这样只需读取方法的签名,就可以判断出是否可以获得可选值。 这会强制您从Optional中获取值并对其进行处理,同时处理Optional可能为空的情况。

4.1、创建 Optional 对象

4.1.1、Optional.empty()

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

Optional<Integer> possible = Optional.empty();
4.1.2、Optional.of()

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

Optional<Integer> possible = Optional.of(5);
4.1.3、Optional.ofNullable()

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

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

4.2、默认/缺省值和操作

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

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

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

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

Optional<Company> 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 的方法

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

返回空的 Optional 实例。

2boolean equals(Object obj)

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

3Optional<T> filter(Predicate<? super <T> predicate)

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

4<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)

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

5T get()

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

6int hashCode()

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

7void ifPresent(Consumer<? super T> consumer)

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

8boolean isPresent()

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

9<U>Optional<U> map(Function<? super T,? extends U> mapper)

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

10static <T> Optional<T> of(T value)

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

11static <T> Optional<T> ofNullable(T value)

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

12T orElse(T other)

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

13T orElseGet(Supplier<? extends T> other)

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

14<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)

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

15String 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/

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,判断空值null值是有区别的。空值是指一个对象没有被实例化,而null值是指一个对象的引用指向了空地址。在判断空值时,可以使用isEmpty()方法来判断字符串是否为空,或者使用length()方法来判断数组是否为空。而在判断null值时,可以使用==运算符来判断一个对象是否为null。此外,还可以使用Optional类来处理可能为空的对象。Optional类是Java 8引入的一个容器类,它可以包装一个对象,如果对象为空,则返回一个空的Optional对象,如果对象非空,则返回一个包含该对象的Optional对象。可以使用Optional的isPresent()方法来判断Optional对象是否为空,或者使用orElse()方法来获取Optional对象中的值,如果为空则返回一个默认值。总之,在Java中判断空值null值的方法有很多种,可以根据具体的需求选择合适的方法来判断。\[2\] #### 引用[.reference_title] - *1* [null空值的判断处理-java](https://blog.csdn.net/Ghost_T/article/details/5811485)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Java如何优雅的进行判空](https://blog.csdn.net/ww2651071028/article/details/130335753)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值