【发布时间】:2015-08-10 14:58:00
【问题描述】:
我在许多网站上阅读过 Optional 应该只用作返回类型,而不是在方法参数中使用。我正在努力寻找一个合乎逻辑的原因。例如,我有一段逻辑,它有 2 个可选参数。因此,我认为像这样编写我的方法签名是有意义的(解决方案 1):
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
// my logic
}
许多网页指定 Optional 不应用作方法参数。考虑到这一点,我可以使用以下方法签名并添加明确的 Javadoc 注释来指定参数可能为空,希望未来的维护人员会阅读 Javadoc,因此在使用参数之前始终执行空检查(解决方案 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 的对象中检索两个输入参数,然后调用calculateSomething。因此,如果使用解决方案 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();
}
}
所以我的问题是:为什么将 Optionals 用作方法参数被认为是不好的做法(请参阅解决方案 1)? 这对我来说似乎是最易读的解决方案,并且最明显参数对于未来的维护者来说可能是空的/null。 (我知道Optional 的设计者打算将其仅用作返回类型,但我找不到在这种情况下不使用它的任何合乎逻辑的理由)。
【问题讨论】:
-
如果你使用了可选参数,你是不是必须检查作为参数传递的可选参数不是
null? -
是的,但是对于将来维护代码的其他人来说,参数可以为空/null,因此可能会避免将来出现空指针异常
-
理论上可能为 null 的所有内容都类似于库中可能调用 System.exit(0) 的每个方法。您不能检查 tis,也不应该检查 this。您必须一直做的所有事情,实际上您应该(几乎)永远不要做。就像将所有参数设为最终参数一样。让您的工具帮助您防止更改参数值或忘记初始化字段,而不是让您的代码无法被数千个 final 和尽可能多的 null 检查所读取。
-
实际上只使用 NonNull/Nullable 注释,这就是您在这种情况下要寻找的,而不是可选的。
-
不太理解 Optional 本身可以为 null 的说法。如果您确定在您的代码库中没有空值(在您确保外部库的每个边界中),那么您可以放心没有空值。我在这样的代码库中工作了 2 年,但我们从未获得过 NPE。现在在一个想要使用解决方案 2 的代码库中,我们每隔几周就会得到 NPE,所以它再好不过了,抱歉。我每次都保证解决方案 1。 Scala 也这样做,没有人考虑空值。我也认为 kotlin