手记

Java 8的Optional类:告别空指针异常

介绍

每个Java开发者在开发应用的过程中,都曾碰到过NullPointerException。虽然通常它被视为一个简单的异常,可以通过避免来解决,但随着应用变得更大更复杂,找到具体的问题原因变得越来越难。为了解决这个问题,Java 8 引入了Optional类,旨在帮助开发者更优雅地处理空值问题,并减少遇到NullPointerException的机会。

Java 中的可选类型

Optional 如何帮助我写出更好的代码片段
如何避免空指针异常

Optional的一个主要作用是避免空指针异常,这样你就可以避免直接处理空值。

明确的意图
  • 当我开始使用 Optional 时,最先遇到的是它能保护代码免受臭名昭著的 NullPointerException 的困扰。
  • 我记得在一个旧项目中,有大量的代码在检查空值,这变得很繁琐。
  • 我们决定将一些方法重构为返回 Optional 而不是可空类型。几乎立刻,我们注意到 NullPointerException 错误减少了,代码变得更干净和可预测。我们不再需要进行多重空值检查,而是使用 ifPresent() 等方法来确保我们只对实际存在的值进行操作。
  • Optional 帮助清晰地传达代码的意图,与其返回 null 来表示值不存在,你可以返回 Optional.empty() 来表示没有值存在。
功能风格方法

当我刚开始接触Java中的函数式编程概念时,Optional 是入门。我特别喜欢 map()filter()ifPresent() 这些方法,它们让我可以编写更简洁和更具表达力的代码。

创建一个可选的对象

我们可以用三种方法来创建可选对象(Optional对象)

  1. 空可选 — 如果我们想创建一个没有任何值的可选
Optional<String> strEmptyOptional = Optional.empty(); 这行代码表示创建了一个空的 Optional 对象。

2. 非空值(non-null value): 如果你有一个非空值并且你想创建一个 Option 对象。

创建了一个非空的Optional对象,该对象包含字符串"Hello"。

3. OfNullable(可能为空): 如果值可能为空,则使用 Optional.ofNullable()。它会返回一个空的 Optional,如果有值即返回 Optional 包含该值。

无需翻译

    Optional<String> nullableOptional = Optional.ofNullable(someString);

Optional 的方法

以下是一些常用的,常用的选项方法——

**isPresent()**:判断 Optional 是否有非空内容。

    Optional<String> optional = Optional.of("Hello");  
    if (optional.isPresent()) {  
        System.out.println("值为: " + optional.get());  //这段代码创建了一个包含字符串"Hello"的Optional对象,并检查它是否包含值,如果有,就打印出来。
    }

**ifPresent()**:如果值存在(即非空值),则执行给定的动作。这在需要进行副作用操作时很有用,例如记录日志或更新用户界面。

    optional.ifPresent(value -> System.out.println("值为: " + value));

**get()**:返回存在的值。注意:如果对空的 Optional 调用 get(),会抛出 NoSuchElementException,使用时要小心。

// 获取 Optional 对象中的字符串值并赋值给变量 value。
String value = optional.get();

**orElse()**:如果有值则返回该值,否则返回默认值。

    String value = optional.orElse("默认值"); // 默认值

**orElseGet()**:类似于 orElse(),但默认值是通过一个供应方提供,采用惰性求值方式。

    String value = optional.orElseGet(() -> "默认值");

这行代码将可选的值赋给一个字符串变量,如果可选值不存在,则会执行一个提供的函数,这里提供了一个返回默认值“默认值”的lambda表达式。

**orElseThrow()**:如果有值则返回,如果没有值则抛出指定异常。

    String value = optional.orElseThrow(() -> new 非法参数异常("如果值不存在,则会抛出异常"));

**map()**:如果有值,则对其进行转换,否则返回一个空的 Optional。这在进行一系列链式操作时非常有用。

Optional<String> upperCaseValue = optional.map(String::toUpperCase);
// 可选的大写值 = 可选.映射(字符串::转换为大写)

**filter()**:根据条件筛选Optional中的值。如果值不符合条件,则返回空的Optional

Optional<String> filteredValue = optional.filter(s -> s 的长度大于5);

**flatMap()**:类似于 map(),但是传递给 flatMap() 的函数必须返回一个 Optional 对象。这在处理嵌套 Optional 值时非常有用。

// 计算可选字符串的长度
Optional<Integer> length = optional.flatMap(s -> Optional.of(s.length()));
避免 NullPointerException 的示例方法(可选)
    import java.util.Optional;  

    public class OptionalExample {  
        public static void main(String[] args) {  
            String name = null;  

            // 创建一个可能包含 null 值的 Optional 对象  
            Optional<String> optionalName = Optional.ofNullable(name);  

            // 检查值是否存在  
            optionalName.ifPresent(value -> System.out.println("Name: " + value));  

            // 使用 orElse() 提供默认值,当值不存在时  
            String result = optionalName.orElse("Default Name");  
            System.out.println(result);  // 输出: Default Name  

            // 在值不存在时抛出异常  
            try {  
                String value = optionalName.orElseThrow(() -> new IllegalArgumentException("名称缺失"));  
            } catch (IllegalArgumentException e) {  
                System.out.println(e.getMessage());  // 输出: 名称缺失  
            }  

            // 转换 Optional 中的值  
            Optional<String> upperCaseName = optionalName.map(String::toUpperCase);  
            System.out.println(upperCaseName.orElse("No Name"));  // 输出: No Name (因为 name 为 null)  
        }  
    }
在什么情况下不要使用 Optional.

虽然 Optional 是一个强大的工具,但并不总是最佳选择。以下是一些使用 Optional 可能不是最佳选择的情况:

  1. 对于实体或POJO中的字段: 避免在实体或JavaBean的字段中使用Optional,因为它会在数据模型结构中引入不必要的复杂性,而这些结构通常会被序列化或反序列化。
  2. 在集合或流中: 不应将Optional用作集合中值的包装器(比如,List<Optional<T>>)。相反,当处理单个值或返回值时使用Optional
  3. 性能考虑: 如果性能至关重要,使用Optional可能会引入额外的开销。如果在您的领域中空值很常见,可以考虑其他设计模式(例如Null Object模式)或直接进行空值检查。
结尾

在 Java 中,Optional 是一个很好的处理可选值的工具,可以避免与 null 相关的麻烦,使代码更健壯并易于阅读。然而,它应该在适当的情况下谨慎使用,尤其是在方法返回类型上,当不存在值是有意义的时候。

关注我们,学习愉快 :)

0人推荐
随时随地看视频
慕课网APP