猿问

为什么不能在参数中使用Java 8的可选性?

为什么不能在参数中使用Java 8的可选性?

我在许多网站上阅读过,可选的应该仅作为返回类型使用,而不是在方法参数中使用。我很难找到合理的理由。例如,我有一个逻辑,它有两个可选的参数。因此,我认为这样写我的方法签名(解决方案1)是有意义的:

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

许多网页指定的可选参数不应用作方法参数。考虑到这一点,我可以使用以下方法签名并添加一个清晰的Javadoc注释来指定参数可能为null,希望未来的维护人员能够读取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}

现在,我尝试编写类的代码,它为每种方法调用这段逻辑。我首先从返回的另一个对象中检索两个输入参数。Optional然后,我调用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)?在我看来,这是最容易读懂的解决方案,而且最明显的是,对于未来的维护人员来说,参数可能是空/空的。(我知道设计师们Optional只打算作为返回类型使用,但我找不到任何逻辑上的理由不使用它在这个场景中)。


慕标5832272
浏览 648回答 3
3回答

呼啦一阵风

哦,那些编码风格要用一点盐。(+)将一个可选的结果传递给另一个方法,而不进行任何语义分析;将该结果留给该方法是很好的。(-)使用可选参数导致方法中的条件逻辑实际上是相反的。(-)需要将参数打包到可选中,对于编译器来说不是最优的,并且需要进行不必要的包装。(-)与可空参数相比,可选参数的开销更大。一般情况下:可选统一了两个州,这两个州必须拆解。因此,结果比输入更适合于数据流的复杂性。

米琪卡哇伊

虽然考虑可选的方法参数不是强制性的,但与其他可能的替代方案相比,这样的解决方案显得微不足道。为了说明这个问题,请检查以下构造函数声明:public&nbsp;SystemMessage(String&nbsp;title,&nbsp;String&nbsp;content,&nbsp;Optional<Attachment>&nbsp;attachment)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;assigning&nbsp;field&nbsp;values}乍一看,这可能是一个正确的设计决策。毕竟,我们显式地将附件参数标记为可选参数。但是,对于调用构造函数,客户端代码可能会变得有点笨拙。SystemMessage&nbsp;withoutAttachment&nbsp;=&nbsp;new&nbsp;SystemMessage("title",&nbsp;"content",&nbsp;Optional.empty()); Attachment&nbsp;attachment&nbsp;=&nbsp;new&nbsp;Attachment(); SystemMessage&nbsp;withAttachment&nbsp;=&nbsp;new&nbsp;SystemMessage("title",&nbsp;"content",&nbsp;Optional.ofNullable(attachment));可选类的工厂方法没有提供清晰性,而只是分散了读者的注意力。注意,只有一个可选参数,但假设有两个或三个参数。鲍勃叔叔肯定不会为这样的代码?感到骄傲当一种方法可以接受可选参数时,最好采用行之有效的方法,并使用方法过载来设计这种情况。在SystemMessage类的示例中,声明两个单独的构造函数优于使用可选构造函数。public&nbsp;SystemMessage(String&nbsp;title,&nbsp;String&nbsp;content)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;this(title,&nbsp;content,&nbsp;null);}public&nbsp;SystemMessage(String&nbsp;title,&nbsp;String&nbsp;content,&nbsp;Attachment&nbsp;attachment)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;assigning&nbsp;field&nbsp;values}这种更改使客户端代码更简单、更易于阅读。SystemMessage&nbsp;withoutAttachment&nbsp;=&nbsp;new&nbsp;SystemMessage("title",&nbsp;"content"); Attachment&nbsp;attachment&nbsp;=&nbsp;new&nbsp;Attachment();SystemMessage&nbsp;withAttachment&nbsp;=&nbsp;new&nbsp;SystemMessage("title",&nbsp;"content",&nbsp;attachment);
随时随地看视频慕课网APP

相关分类

Java
我要回答