6.1 Optional的创建
问题
用户希望从现有值返回 Optional。
方案
使用 Optional.of、Optional.ofNullable 或 Optional.empty 方法。
讨论
与 Java 8 新增的众多类一样,Optional 实例也是不可变的(immutable)。API 将 Optional 称为基于值的类(value-based class),即 Optional 实例:
- 被声明为
final且是不可变 2 的(但可能包含对可变对象的引用); - 不提供公共构造函数(public constructor),因此必须采用工厂方法加以实例化;
- 具有
equals、hashCode与toString的实现,这些实现是通过实例的状态计算出来的。
2有关不可变性的讨论请参见“Optional 与不可变性”注释。
Optional与不可变性
Optional实例是不可变的,但它包装的对象却不一定是不可变的。如果创建一个包含可变对象实例的Optional,则仍然可以对实例进行修改,如例 6-1 所示。例 6-1
Optional是不可变的吗?
- AtomicInteger counter = new AtomicInteger();
- Optional<AtomicInteger> opt = Optional.ofNullable(counter);
- System.out.println(optional); // Optional[0]
- counter.incrementAndGet(); ➊
- System.out.println(optional); // Optional[1]
- optional.get().incrementAndGet(); ➋
- System.out.println(optional); // Optional[2]
- optional = Optional.ofNullable(new AtomicInteger()); ➌
❶ 直接使用计数器自增
❷ 检索包含的值并自增
❸ 可以对
Optional引用重新赋值我们既可以通过原始引用修改包含的值,也可以在
Optional上调用get以检索某个值进行修改。我们甚至可以对引用本身重新赋值,换言之,不能将不可变性与 final 混为一谈。但是,无法对Optional实例本身进行修改,因为不存在能执行这种操作的方法。对“不可变”的定义略显模糊,这在 Java 中并不鲜见。Java 并未提供一种良好的内置方式来创建只能产生无法改变的对象的类。
我们可以通过静态工厂方法 empty、of 与 ofNullable 来创建 Optional,三者的签名如下:
- static <T> Optional<T> empty()
- static <T> Optional<T> of(T value)
- static <T> Optional<T> ofNullable(T value)
显而易见,empty 方法将返回一个空 Optional。如果参数为 null,of 方法将返回一个包装指定值或抛出异常的 Optional,其应用如例 6-2 所示。
例 6-2 通过
of方法创建Optional
- public static <T> Optional<T> createOptionalTheHardWay(T value) {
- return value == null ? Optional.empty() : Optional.of(value);
- }
在本例中,createOptionalTheHardWay 之所以被命名为“The Hard Way”,并非因为它难以实现,而是存在另一种更简单的方法,这就是例 6-3 所示的 ofNullable 方法。
例 6-3 通过
ofNullable方法创建Optional
- public static <T> Optional<T> createOptionalTheEasyWay(T value) {
- return Optional.ofNullable(value);
- }
在 Java 8 的引用实现中,ofNullable 方法的实现其实就是 createOptionalTheHardWay 中的语句:检查包含的值是否为 null,若是,则返回一个空 Optional,否则使用 of 方法进行包装。
此外,包装基本数据类型的 OptionalInt、OptionalLong 与 OptionalDouble 类不能为 null,因此三者只有 of 方法,没有 ofNullable 方法。
- static OptionalInt of(int value)
- static OptionalLong of(long value)
- static OptionalDouble of(double value)
请注意,三个类的 getter 方法分别为 getAsInt、getAsLong 与 getAsDouble,而不是 getInt、getLong 与 getDouble。
另见
本章其他范例(如范例 6.4 和范例 6.5)根据提供的集合(而非现有值)来创建 Optional 值,范例 6.3 使用本范例讨论的方法来包装提供的值。
