我在许多网站上读到过,Optional应该只用作返回类型,而不能用于方法参数中。我在努力寻找一个合乎逻辑的原因。例如,我有一个逻辑,它有两个可选参数。因此,我认为这样写我的方法签名是有意义的(解决方案1):

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2) {
    // my logic
}

许多网页指定Optional不应该用作方法参数。考虑到这一点,我可以使用下面的方法签名,并添加一个明确的Javadoc注释来指定参数可能为null,希望未来的维护者能够读取Javadoc,因此在使用参数之前总是执行null检查(解决方案2):

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

或者,我可以用四个公共方法替换我的方法,以提供更好的接口,并使p1和p2是可选的(解决方案3):

public int calculateSomething() {
    calculateSomething(null, null);
}

public int calculateSomething(String p1) {
    calculateSomething(p1, null);
}

public int calculateSomething(BigDecimal p2) {
    calculateSomething(null, p2);
}

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

现在,我尝试编写为每种方法调用这段逻辑的类的代码。我首先从另一个返回Optionals的对象检索两个输入参数,然后调用calculatessomething。因此,如果使用解决方案1,调用代码将看起来像这样:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);

如果使用解决方案2,调用代码看起来像这样:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

如果应用解决方案3,我可以使用上面的代码,也可以使用下面的代码(但它的代码明显更多):

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p1, p2);
    } else {
        result = myObject.calculateSomething(p1);
    }
} else {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p2);
    } else {
        result = myObject.calculateSomething();
    }
}

所以我的问题是:为什么使用可选项作为方法参数被认为是不好的做法(参见解决方案1)?对我来说,这看起来是最易读的解决方案,并且对于未来的维护者来说,参数可以是空的/null是最明显的。(我知道Optional的设计者只打算将其用作返回类型,但我找不到在这种情况下不使用它的任何逻辑理由)。


当前回答

我相信存在的原因是你必须首先检查Optional本身是否为null,然后尝试计算它包装的值。太多不必要的验证。

其他回答

哦,这些编码风格应该有所保留。

(+)传递一个可选结果给另一个方法,没有任何语义分析;把它留给方法,是很好的。 (-)在方法中使用可选参数导致条件逻辑是反作用的。 (-)需要将参数打包到Optional中,对编译器来说是次优的,并且做了不必要的包装。 (-)与可空参数相比,Optional的开销更大。 (-)有人在实际参数中传递Optional为空的风险。

总的来说:可选的统一了两个状态,这两个状态必须被分解。因此,由于数据流的复杂性,它更适合于结果而不是输入。

一个很好的例子是可选的参数会很好是JPA存储库。我喜欢做一些像findbynameand姓氏(可选,可选)。这样,如果Optional为空,则不执行WHERE param=y

正如Brian Goetz所解释的那样,可选选项并不是为此目的而设计的。

你总是可以使用@Nullable来表示方法参数可以为空。使用可选方法并不能让你的方法逻辑写得更整齐。

这是因为我们对API用户和API开发人员有不同的要求。

开发人员负责提供精确的规范和正确的实现。因此,如果开发人员已经意识到一个参数是可选的,那么实现必须正确地处理它,无论它是null还是optional。API应该对用户尽可能简单,null是最简单的。

另一方面,结果从API开发人员传递给用户。尽管规范是完整和冗长的,但仍然有可能用户没有意识到它或只是懒得处理它。在这种情况下,Optional结果迫使用户编写一些额外的代码来处理可能为空的结果。

带有Optional的模式是为了避免返回null。将null传递给方法仍然是完全可能的。

虽然这些注释还不是正式的,但您可以使用JSR-308样式注释来指示是否接受函数中的空值。请注意,您必须有正确的工具来实际识别它,它将提供更多的静态检查而不是可执行的运行时策略,但它将有所帮助。

public int calculateSomething(@NotNull final String p1, @NotNull final String p2) {}