Optional使用方式

Optional在jdk8中引入,已经有很长时间了,但是对于它的使用在平时的项目中最多只是拿它做下面这样的处理:

XX e = Optional.ofNullable(xx.xx(x.x()))
                        .orElseThrow(() -> new xxException("xxx"));

判断某个方法返回的值是否为null,如果是会抛出一个异常。

在Optional引入之前处理null都是使用if去判断,这样写起来有点繁琐,但是最主要的还是很容易忘记判断值是否为null。使用可能为null的值去执行程序会出现很多意想不到的结果,可能会抛出NPE,可能出现一些其他的问题。为了避免这些问题所以jdk8引入了Optional去处理,当然上面的例子只是很简单的使用,也可以说不是很正确的使用。

在哪用

  • 在可能为空的成员变量的get方法上使用Optional返回

class Student {
        //name可能为null
        private String name;
        //id肯定不会为null
        private Integer id;

        public Student(String name) {
            this.name = name;
        }

        public Optional<String> getName() {
            return Optional.of(name);
        }
        
        public Integer getId(){
            return id;
        }
    }
  • 不要在set方法和构造方法参数上使用Optional接收参数

在set方法和构造函数上如果使用Optional接收参数会使调用这个方法的人很痛苦,因为它需要包装成Optional然后去调用。最好的做法应该是便利胜过对输入的严格要求。

  • 使用Optional作为业务逻辑方法的返回结果

public Optional<Address> getAdderss(){
            //做一些逻辑处理
            return ...//如果找到了地址则返回对应的地址的Optional,如果没有找到则返回Optional.empty()
        }

看本文开头的例子,就是一种不好的返回方式,应该返回一个被Optional包装的值,而不是直接返回真实的值。

 

如何用

拿到了对应的Optional如何来做处理?

optionalStudent.get().getName();

上面的这种方式直接去使用get去获取Optional中的值是有问题,因为当Optional中包装的值是null,还是会抛出异常。

下面换一种方式确保它不为空再使用。

if(optionalStudent.isPresent()){
     optionalStudent.get().getName();
}

上面的那种方式和以前的写法没有什么区别,没有将Optional的功能用好。也同样存在忘记判断是否为null后再去使用。

   Optional<Student> optionalStudent = Optional.ofNullable(new Student(null));
        System.out.println(optionalStudent.map(Student::getName).orElse("xx"));
        System.out.println(optionalStudent.map(Student::getName).orElseThrow(() -> new Exception()));

class Student {
        private String name;

        public Student(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

    }

可以使用上面的方式获取,如果在值为Student的name为null的情况下,或返回一个指定的字符串“xx”。当然也可以抛出异常。

上面的例子是一个对象里的成员变量是null,如果返回的对象就是null呢,上面的程序还是会一样的执行吗,比如:

//这里给定的是null
Optional<Student> optionalStudent = Optional.ofNullable(null);
        System.out.println(optionalStudent.map(Student::getName).orElse("xx"));
        System.out.println(optionalStudent.map(Student::getName).orElseThrow(() -> new Exception()));

这里还是会和上面执行的结果一样。当然也可以使用ifPresent方法,当值不为null时才会执行里面的代码。

optionalStudent.ifPresent(student -> {
        //不为null时才会执行
            System.out.println(student.getName());
        });

参考资料

https://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html

### 正确使用 `Optional` 的编程方式 #### 使用场景 `Optional` 是 Java 8 中引入的一个容器类,旨在减少因返回值为 `null` 而引发的空指针异常。它通过封装可能为空的对象来强制开发者显式处理潜在的 `null` 值。 #### 创建 `Optional` 对象 可以通过三种主要方法创建 `Optional` 实例[^2]: - **`Optional.empty()`**: 返回一个不包含任何值的 `Optional`。 - **`Optional.of(T value)`**: 返回一个包含指定非空值的 `Optional`。如果传入的是 `null`,会抛出 `NullPointerException`。 - **`Optional.ofNullable(T value)`**: 如果参数为 `null`,则返回一个空的 `Optional`;否则返回包含该值的 `Optional`。 以下是具体示例代码: ```java // 使用 empty() Optional<String> emptyOptional = Optional.empty(); // 使用 of() Optional<String> nonNullValue = Optional.of("Hello"); // 使用 ofNullable() Optional<String> nullableValue = Optional.ofNullable(null); nullableValue.ifPresentOrElse( System.out::println, () -> System.out.println("No Value Present") ); ``` #### 处理 `Optional` 内部值 可以利用种方法安全地访问和操作 `Optional` 容器中的值: 1. **`isPresent()` 和 `ifPresent(Consumer<? super T>)`** - 检查是否有值存在并执行相应逻辑。 ```java Optional<String> optStr = Optional.of("World"); if (optStr.isPresent()) { System.out.println(optStr.get()); } optStr.ifPresent(value -> System.out.println("Value is: " + value)); ``` 2. **`orElse(T other)`** - 当 `Optional` 不含有效值时提供默认替代项。 ```java String result = Optional.ofNullable(null).orElse("Default"); System.out.println(result); // 输出 Default ``` 3. **`orElseGet(Supplier<? extends T> supplier)`** - 类似于 `orElse` 方法,但它允许延迟计算默认值直到必要时刻才触发。 ```java String lazyResult = Optional.ofNullable(null).orElseGet(() -> computeExpensiveOperation()); ``` 4. **`map(Function<? super T, ? extends U> mapper)`** - 将当前值映射到另一个新类型的值上形成新的 `Optional`。 5. **`flatMap(Function<? super T, ? extends Optional<U>> mapper)`** - 执行函数转换的同时保持结果仍然是 `Optional` 形态而不嵌套额外层[^1]。 下面是一个综合运用这些特性的例子: ```java public class User { private final Address address; public User(Address address) { this.address = address; } public Optional<Address> getAddress() { return Optional.ofNullable(address); } } public class Address { private final String city; public Address(String city) { this.city = city; } public String getCity() { return city; } } public static void main(String[] args) { User user = new User(new Address("New York")); Optional<String> cityName = Optional.of(user) .flatMap(User::getAddress) .map(Address::getCity); cityName.ifPresent(System.out::println); // 输出 New York } ``` #### 避免滥用 `Optional` 尽管 `Optional` 提供了许便利功能,但也需要注意其适用范围: - 切勿将其作为字段成员变量存储。 - 不应过度依赖链式调用来掩盖复杂业务逻辑。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值