为什么Java 8的Optable不应该在参数中使用

2022-08-31 04:16:01

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

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

许多网页指定“可选”不应用作方法参数。考虑到这一点,我可以使用以下方法签名并添加一个清晰的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
}

现在,我尝试编写该类的代码,该代码为每个方法调用这段逻辑。我首先从另一个返回s的对象中检索两个输入参数,然后调用。因此,如果使用解决方案 1,则调用代码将如下所示:OptionalcalculateSomething

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();
    }
}

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


答案 1

哦,这些编码风格是用一点盐来取的。

  1. (+)将可选结果传递给另一个方法,无需任何语义分析;把它留给方法,是相当好的。
  2. (-)使用可选参数在方法中引起条件逻辑实际上是相反的。
  3. (-)需要在 Optional 中打包参数对于编译器来说是次优的,并且会执行不必要的包装。
  4. (-)与可为空的参数相比,可选的代价更高。
  5. (-)有人在实际参数中将 Optional 作为 null 传递的风险。

一般而言:可选统一了两个必须解开的状态。因此,对于数据流的复杂性,它更适合结果而不是输入。


答案 2

我见过的关于这个话题的最好的帖子是由Daniel Olszewski写的:

尽管考虑非强制性方法参数的可选可能很诱人,但与其他可能的替代方案相比,这样的解决方案相形见绌。为了说明问题,请检查以下构造函数声明:

public SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}

乍一看,它可能看起来像是一个正确的设计决策。毕竟,我们显式地将附件参数标记为可选。但是,至于调用构造函数,客户端代码可能会变得有点笨拙。

SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));

Optional 类的工厂方法不仅没有提供清晰度,反而会分散读者的注意力。请注意,只有一个可选参数,但想象一下有两个或三个。鲍勃叔叔绝对不会为这样的代码感到自豪。


推荐