4.Optional

4.Optional

4.1 概述

我们在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。

例如:

Author author = getAuthor();
if(author!=null){
	system.out.println(author.getName());
}

尤其是对象中的属性还是一个对象的情况下。这种判断会更多。

而过多的判断语句会让我们的代码显得臃肿不堪。

所以在JDK8中引入了Optional,养成使用Optional的习惯后你可以写出更优雅的代码来避免空指针异常。

并且在很多函数式编程相关的API中也都用到了Optional,如果不会使用Optional也会对函数式编程的学习造成影响。

4.2 使用

4.2.1 创建对象

optional就好像是包装类,可以把我们的具体数据封装Optional对象内部。然后我们去使用Optional中封装好的方法操作封装进去的数据就可以非常优雅的避免空指针异常。

我们一般使用Optional静态方法ofNullable来把数据封装成一个Optional对象。无论传入的参数是否为null都不会出现问题。

Author author = getAuthor();
optional<Author> authoroptional = optional.ofNullable(author);

你可能会觉得还要加一行代码来封装数据比较麻烦。但是如果改造下getAuthor方法,让其的返回值就是封装好的Optional的话,我们在使用时就会方便很多。

import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args) {
        Optional<Author> authorOptional = getAuthorOptional();
        authorOptional.ifPresent(author -> System.out.println(author.getName()));
    }


    public static Optional<Author> getAuthorOptional(){
        Author author = new Author(1L, "梦多", 33, "梦开始的地方", null);
        return Optional.ofNullable(author);
    }
}

而且在实际开发中我们的数据很多是从数据库获取的。Mybatis从3.5版本可以也已经支持Optional了。我们可以直接把dao方法的返回值类型定义成Optional类型,MyBastis会自己把数据封装成Optional对象返回。封装的过程也不需要我们自己操作。

4.2.2 安全消费值

我们获取到一个Optional对象后肯定需要对其中的数据进行使用。这时候我们可以使用其ifPresent方法对来消费其中的值。这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码。这样使用起来就更加安全了。
例如,以下写法就优雅的避免了空指针异营。

optional<Author> authoroptional = optional.ofNullable(getAuthor();
                                                      
authorOptional.ifPresent(author -> System.out.print1n(author .getName());
4.2.3 获取值

如果我们期望安全的获取值。我们不推荐使用get方法,而是使用Optional提供的以下方法。

4.2.4 安全获取值
  • orElseGet

  • 获取数据并且设置数据为空时的默认值。如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建对象作为默认值返回。

      Optional<Author> authorOptional = getAuthorOptional();
            Author author = authorOptional.orElseGet(() -> new Author());
            System.out.println(author.getName());
    
  • orElseThrow

    获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常抛出

       Optional<Author> authorOptional = getAuthorOptional();
            try {
                Author author = authorOptional.orElseThrow(() -> new RuntimeException("数据为null"));
                System.out.println(author);
            }catch (Throwable throwable){
                throwable.printStackTrace();
            }
    
4.2.5 过滤

我们可以使用filter方法对数据进行过滤。如果原本是有数据的,但是不符合判断,也会变成一个无数据的Optional对象。

 Optional<Author> authorOptional = getAuthorOptional();
        authorOptional.filter(author -> author.getAge()>18).ifPresent(author -> System.out.println(author.getName()));

4.2.6 判断

​ 我们可以使用isPresent方法进行是否存在数据的判断。如果为空返回值为false,如果不为空,返回值为true。但是这种方式并不能体现optional的好处,更推荐使用ifPresent方法。

  Optional<Author> authorOptional = getAuthorOptional();
        if (authorOptional.isPresent()) {
            System.out.println(authorOptional.get().getName());
            System.out.println(authorOptional.get().getAge());
        }
4.2.7 数据转换

​ optionali还提供了map可以让我们的对数据进行转换,并且转换得到的数据也还是被Optional包装好的,保证了我们的使用安全。

例如我们想获取作家的书籍集合。

   Optional<Author> authorOptional = getAuthorOptional();
        Optional<List<Book>> optionalBooks = authorOptional.map(author -> author.getBooks());
        optionalBooks.ifPresent(books-> System.out.println(books));

Java 的 `Optional` 类中,`orElse` 和 `orElseGet` 方法用于在 `Optional` 实例为空时提供默认值。两者在行为上存在显著差异,特别是在触发 `getDefaultValue` 方法的执行时机上。 ### `orElse` 方法的行为 `orElse` 方法的签名如下: ```java public T orElse(T other) ``` 此方法无论 `Optional` 实例是否为空,都会**直接计算并返回传入的默认值**。这意味着即使 `Optional` 实例中已经包含非空值,传入 `orElse` 的默认值仍然会被计算,包括调用 `getDefaultValue` 方法。例如: ```java String result = Optional.of("Hello").orElse(getDefaultValue()); ``` 在此代码中,即使 `Optional` 包含 `"Hello"`,`getDefaultValue()` 仍会在进入 `orElse` 方法前被调用,导致不必要的资源消耗。 ### `orElseGet` 方法的行为 `orElseGet` 方法的签名如下: ```java public T orElseGet(Supplier<? extends T> supplier) ``` 此方法仅在 `Optional` 实例为空时才会调用 `Supplier` 提供的函数式接口来获取默认值。这意味着 `getDefaultValue()` 方法只有在需要时才会被调用。例如: ```java String result = Optional.of("Hello").orElseGet(() -> getDefaultValue()); ``` 在此代码中,由于 `Optional` 已包含非空值,`getDefaultValue()` 方法不会被调用,从而避免了不必要的执行。 ### 总结 - `orElse` 会在任何情况下执行 `getDefaultValue()` 方法,即使 `Optional` 实例不为空[^1]。 - `orElseGet` 只有在 `Optional` 实例为空时才会执行 `getDefaultValue()` 方法,从而实现延迟求值的效果。 因此,在性能敏感或默认值计算代价较高的场景下,推荐使用 `orElseGet` 来避免不必要的方法调用。 ### 示例代码 ```java public class OptionalExample { private static String getDefaultValue() { System.out.println("Executing getDefaultValue()"); return "default"; } public static void main(String[] args) { // orElse 会执行 getDefaultValue() String result1 = Optional.of("Hello").orElse(getDefaultValue()); // orElseGet 不会执行 getDefaultValue() String result2 = Optional.of("Hello").orElseGet(OptionalExample::getDefaultValue()); } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值