使用 Optional 实现空值安全
在上一步中,我们学习了如何通过在使用对象之前显式检查对象是否为 null
来防止 NullPointerException
。虽然这种方法很有效,但有时会导致代码中充斥着大量的空值检查。Java 8 引入了 Optional
类,以一种更具函数式和表现力的方式来处理可能为 null
的值。
Optional
是一个容器对象,它可能包含也可能不包含非空值。如果存在值,isPresent()
方法返回 true
,get()
方法返回该值。如果不存在值,则该对象被视为空,isPresent()
方法返回 false
。对空的 Optional
对象调用 get()
方法会抛出 NoSuchElementException
。
让我们重构我们的示例,使用 Optional<Character>
来处理 Character
可能为 null
的情况。
-
在 WebIDE 编辑器中打开 HelloJava.java
文件。
-
将文件的全部内容替换为以下代码:
import java.util.Optional;
public class HelloJava {
public static void main(String[] args) {
Character myChar = null; // 仍然可能为 null
// 从可能为 null 的 Character 创建一个 Optional
Optional<Character> optionalChar = Optional.ofNullable(myChar);
// 使用 Optional 方法检查和处理值
if (optionalChar.isPresent() && Character.isLetter(optionalChar.get())) {
System.out.println("myChar is a letter.");
} else {
System.out.println("myChar is not a letter or is null.");
}
// 另一种使用 Optional 函数式方法的方式(更高级)
// optionalChar.filter(Character::isLetter)
// .ifPresentOrElse(
// c -> System.out.println("myChar is a letter (using Optional methods)."),
// () -> System.out.println("myChar is not a letter or is null (using Optional methods).")
// );
}
}
在这段代码中:
- 我们导入了
Optional
类。
- 我们仍然将
myChar
声明为可能为 null
。
Optional<Character> optionalChar = Optional.ofNullable(myChar);
创建了一个 Optional
对象。Optional.ofNullable()
用于处理值可能为 null
的情况。如果 myChar
为 null
,optionalChar
将是一个空的 Optional
。如果 myChar
有值,optionalChar
将包含该值。
- 然后,我们使用
optionalChar.isPresent()
检查 Optional
是否包含值,然后再使用 optionalChar.get()
获取该值并将其传递给 Character.isLetter()
。这与我们之前的空值检查类似,但使用了 Optional
API。
- 注释掉的部分展示了一种更高级的使用
Optional
的方式,使用了 filter
和 ifPresentOrElse
等函数式方法,在某些场景下可以使代码更简洁。在这个入门实验中,我们不会关注这种高级用法,但了解一下是有好处的。
-
保存文件。
-
编译程序:
javac HelloJava.java
-
运行程序:
java HelloJava
输出应该与上一步相同:
myChar is not a letter or is null.
这证实了使用 Optional.ofNullable()
和 isPresent()
可以正确处理空值情况。
现在,让我们将 myChar
改为一个非空字符,看看程序的行为。
-
修改 HelloJava.java
文件,将 myChar
设置为一个字符,例如 'A':
import java.util.Optional;
public class HelloJava {
public static void main(String[] args) {
Character myChar = 'A'; // 现在 myChar 有值了
// 从可能为 null 的 Character 创建一个 Optional
Optional<Character> optionalChar = Optional.ofNullable(myChar);
// 使用 Optional 方法检查和处理值
if (optionalChar.isPresent() && Character.isLetter(optionalChar.get())) {
System.out.println("myChar is a letter.");
} else {
System.out.println("myChar is not a letter or is null.");
}
}
}
-
保存文件。
-
编译程序:
javac HelloJava.java
-
运行程序:
java HelloJava
这次,输出应该是:
myChar is a letter.
这表明当 myChar
有值时,optionalChar.isPresent()
返回 true
,并且 Character.isLetter()
检查能正确执行。
使用 Optional
可以使你的代码更易读,并明确指出值可能缺失的情况,从而降低意外出现 NullPointerException
的可能性。