{一起看DZone}Optional 其实很渣渣

大家好,我是William。

前几天我在DZone上看到了一篇文章《Optional Anti-Patterns》,该文章的作者列举了数个关于 Java8 的 Optional 类的各种反模式例子,看得我心惊肉跳的,毕竟前几个月才用过这个东西,当时觉得很酷炫,直到最近我接触到 Kotlin 这门语言后,才发现其实空指针的检查应该交给编译器来做,而不是开发者自己去约束自己。反正目前,我觉得 Optional 真的很渣渣(不服来战,我在评论区等着你)。

文章的链接:
https://dzone.com/articles/optional-anti-patterns

下面我将会把文章的中心思想和代码给大家过一遍,顺便中间夹杂个人观点。

第一宗罪:在字段上用 Optional

public class Car {
    private List wheels;
    private Optional engine;

    // getter and setter
}

上面的代码问题出现在哪?
实际上,Optional 是不可以参与序列化的,这就很坑了。但是,我又担心 engine 是空的,想用 Optional 来挡一下;又想让 engine 参与序列化,该怎么办呢?

下面的代码给出了优化方案:

public class Car {
    private List wheels;
    private Engine engine;

    // 很稳健
    public Optional getEngine() {
        return Optional.ofNullable(engine);
    }
}

第二宗罪:集合中的元素都是 Optional 的

// 内心很崩溃吧
private List> wheels;

大家千万别像上面这么写集合啊,谁会这么傻在调用 wheels.add() 的时候传入一个 null 值,倘若真的传入了,则直接跑出 NullPointsException 异常。所以上面的写法属于过度设计。

第三宗罪:在方法的形参上用 Optional

我们都知道 Optional 提供了几个静态工厂方法,让开发者方便创建 Optional 对象,看起来貌似很酷炫。

Optional.empty()
Optional.of(T value)
Optional.ofNullable(T value)

但是如果在方法的形参上用 Optional ,画面应该是这样的:

// 声明一个方法
Long calculate(List> data) { ... }

// 然后调用它
List data = Arrays.asList(1L, 2L);
calculate(Optional.of(data));

这里的例子跟第二宗罪的例子有联系,说好的不要在集合中使用 Optional 作为元素的类型。所以正常的画面应该如下:

// 假设方法的形参没有 Optional
List data = Arrays.asList(1L, 2L);
calculate(data);

我再补充一个稍微典型一点的:

// 声明一个方法
Long max(Optional a, Optional b) { ... }

// 妈的智障
max(Optional.of(1L), Optional.of(2L));

第四宗罪:强制序列化 Optional

哎,这里不多说,作者是直接引用 javadoc 的经文,我这里也直接贴出:

"This is a value-based class; use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided"
— from the Javadoc.

不过,作者也提到一个 Java 在路上的项目叫 Project Valhalla ,将会支持 Optional 序列化,不过要等 Java 版本更新是件很痛苦的事情,再等企业主动更新自己的 JDK 版本又是件很痛苦的事情,现在还有很多企业的项目居然还在用 JDK6,简直不忍直视。

不严谨的结论

目前来说,Optional 很渣渣,还不如 Kotlin 来得直接。

你可能感兴趣的:({一起看DZone}Optional 其实很渣渣)