Java的可选性并不取代所有传统的if-null-else或if-not-null-else检查

317 阅读3分钟

Java的可选性并不取代所有传统的if-null-else或if-not-null-else检查

Java增加的java.util.Optional受到了欢迎,对于不能总是返回null 值的方法,它曾带来了更流畅的代码。不幸的是,Optional滥用了,其中一种类型的滥用是过度使用。我偶尔会遇到一些使用Optional的代码,这些代码与直接使用null 相比并没有明显的优势。

当调用代码使用Optional.ofNullable(T)来对付它刚刚调用的方法的返回值时,一个红色的标志可以提示我们,Optional 的使用比直接检查null 没有优势。就像所有的 "红旗"一样,这并不意味着将方法的返回值传递给Optional.ofNullable(T) 一定是件坏事(事实上,有必要传递给期待Optional 的API),但这种方法通常被用来提供比直接使用返回值和检查null 更多的实际价值。

Optional可用之前,检查从一个方法返回的null ,并对null 响应采取一种行动,对非null 响应采取另一种行动的代码如下所示(这篇文章中的所有代码片段都可以在GitHub上找到):

/**
 * Demonstrates approach to conditional based on {@code null} or
 * not {@code null} that is traditional pre-{@link Optional} approach.
 */
public void demonstrateWithoutOptional()
{
    final Object returnObject = methodPotentiallyReturningNull();
    if (returnObject == null)
    {
        out.println("The returned Object is null.");
    }
    else
    {
        out.println("The returned object is NOT null: " + returnObject);
        // code processing non-null return object goes here ...
    }
}

对于这种基本条件,很少有必要涉及Optional 。下一个代码片断是我偶尔看到的代码类型的代表,当开发者试图用使用Optional来取代显式的null

/**
 * Demonstrates using {@link Optional} in exactly the manner {@code null}
 * is often used (conditional on whether the returned value is empty or
 * not versus on whether the returned value is {@code null} or not).
 */
public void demonstrateOptionalUsedLikeNullUsed()
{
    final Optional<Object> optionalReturn
       = Optional.ofNullable(methodPotentiallyReturningNull());
    if (optionalReturn.isEmpty())
    {
        out.println("The returned Object is empty.");
    }
    else
    {
        out.println("The returned Object is NOT empty: " + optionalReturn);
        // code processing non-null return object goes here ...
    }
}

这段代码中的范式与传统的null-检查代码基本相同,但使用Optional.isEmpty()来执行相同的检查。这种方法没有增加任何可读性或其他优势,但确实付出了一个额外的对象实例化和方法调用的小代价。

上述使用Optional 的一个变种是将其ifPresent(Consumer)方法与isEmpty()方法结合使用,形成相同的基本逻辑,即如果返回值是存在的,就做一件事,如果返回值是空的,就做另一件事。这在下面的代码中得到了证明:

/**
 * Demonstrates using {@link Optional} methods {@link Optional#ifPresent(Consumer)}
 * and {@link Optional#isEmpty()} in similar manner to traditional condition based
 * on {@code null} or not {@code null}.
 */
public void demonstrateOptionalIfPresentAndIsEmpty()
{
    final Optional<Object> optionalReturn
       = Optional.ofNullable(methodPotentiallyReturningNull());
    optionalReturn.ifPresent(
       (it) -> out.println("The returned Object is NOT empty: " + it));
    if (optionalReturn.isEmpty())
    {
        out.println("The returned object is empty.");
    }
}

这段代码看起来比直接检查返回值的传统方法要短一些,null ,但仍然要付出额外的对象实例化的代价,并且需要两个方法的调用。此外,首先检查Optional是否存在,然后立即检查是否为空,这感觉有点奇怪。另外,如果需要执行的逻辑比向标准输出写出一条消息更复杂,这种方法就变得不那么有效了。

结论

处理一个方法的返回值的代码,如果返回值是null ,需要做一件事,如果返回值不是 null ,需要做另一件事,那么用Optional ,简单地检查返回值是否存在或为空,很少能享受到任何好处。将方法的返回值包裹在一个Optional 中,只有在该Optional 被用于流畅链或与Optional 一起工作的API中时,才可能值得花钱。