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

本文翻译自:Why should Java 8's Optional not be used in arguments

I've read on many Web sites Optional should be used as a return type only, and not used in method arguments. 我已经在许多网站上阅读了Optional应该仅用作返回类型,而不能在方法参数中使用。 I'm struggling to find a logical reason why. 我正在努力寻找一个合理的理由。 For example I have a piece of logic which has 2 optional parameters. 例如,我有一段逻辑,其中包含2个可选参数。 Therefore I think it would make sense to write my method signature like this (solution 1): 因此,我认为这样写我的方法签名将是有意义的(解决方案1):

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

Many web pages specify Optional should not be used as method arguments. 许多指定为Optional的网页不应用作方法参数。 With this in mind, I could use the following method signature and add a clear Javadoc comment to specify that the arguments may be null, hoping future maintainers will read the Javadoc and therefore always carry out null checks prior to using the arguments (solution 2): 考虑到这一点,我可以使用以下方法签名并添加清晰的Javadoc注释以指定参数可以为null,希望以后的维护者将读取Javadoc,因此始终在使用参数之前进行null检查(解决方案2) :

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

Alternatively I could replace my method with four public methods to provide a nicer interface and make it more obvious p1 and p2 are optional (solution 3): 或者,我可以用四个公共方法替换我的方法,以提供更好的接口,并使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
}

Now I try writing the code of the class which invokes this piece of logic for each approach. 现在,我尝试编写该类的代码,每种方法都会调用此逻辑。 I first retrieve the two input parameters from another object which returns Optional s and then, I invoke calculateSomething . 我首先从另一个返回Optional的对象中检索两个输入参数,然后调用calculateSomething Therefore, if solution 1 is used the calling code would look like this: 因此,如果使用解决方案1,则调用代码将如下所示:

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

if solution 2 is used, the calling code would look like this: 如果使用解决方案2,则调用代码将如下所示:

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

if solution 3 is applied, I could use the code above or I could use the following (but it's significantly more code): 如果应用了解决方案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();
    }
}

So my question is: Why is it considered bad practice to use Optional s as method arguments (see solution 1)? 所以我的问题是:为什么将Optional用作方法参数被认为是不好的做法(请参阅解决方案1)? It looks like the most readable solution to me and makes it most obvious that the parameters could be empty/null to future maintainers. 对我来说,这似乎是最易读的解决方案,并且对于将来的维护人员来说,最明显的是参数可以为空/空。 (I'm aware the designers of Optional intended it to only be used as a return type, but I can't find any logical reasons not to use it in this scenario). (我知道Optional的设计者打算将其仅用作返回类型,但在这种情况下我找不到任何不使用它的逻辑原因)。


#1楼

参考:https://stackoom.com/question/29waw/为什么不应该在参数中使用Java-的Optional


#2楼

I think that is because you usually write your functions to manipulate data, and then lift it to Optional using map and similar functions. 我认为这是因为通常编写函数来处理数据,然后使用map和类似函数将其提升为Optional This adds the default Optional behavior to it. 这将为其添加默认的Optional行为。 Of course, there might be cases, when it is necessary to write your own auxilary function that works on Optional . 当然,在某些情况下,有必要编写自己的对Optional起作用的辅助函数。


#3楼

I believe the reson of being is you have to first check whether or not Optional is null itself and then try to evaluate value it wraps. 我相信,存在的共鸣是您必须首先检查Optional是否为null,然后尝试评估它包装的值。 Too many unnecessary validations. 太多不必要的验证。


#4楼

The pattern with Optional is for one to avoid returning null . 带有Optional的模式是为了避免返回 null It's still perfectly possible to pass in null to a method. 仍然可以将null传递给方法。

While these aren't really official yet, you can use JSR-308 style annotations to indicate whether or not you accept null values into the function. 尽管这些还不是真正的官方,但是您可以使用JSR-308样式注释来指示您是否在函数中接受null值。 Note that you'd have to have the right tooling to actually identify it, and it'd provide more of a static check than an enforceable runtime policy, but it would help. 请注意,您必须具有正确的工具来实际识别它,并且它提供的静态检查多于可执行的运行时策略,但这会有所帮助。

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

#5楼

Oh, those coding styles are to be taken with a bit of salt. 哦,这些编码风格要花点儿力气。

  1. (+) Passing an Optional result to another method, without any semantic analysis; (+)将Optional结果传递给另一种方法,而无需任何语义分析; leaving that to the method, is quite alright. 将其留给方法,是完全可以的。
  2. (-) Using Optional parameters causing conditional logic inside the methods is literally contra-productive. (-)使用可选参数在方法内部引起条件逻辑实际上是相反的。
  3. (-) Needing to pack an argument in an Optional, is suboptimal for the compiler, and does an unnecessary wrapping. (-)需要将参数打包在Optional中,对于编译器来说不是最佳选择,并且不需要进行包装。
  4. (-) In comparison to nullable parameters Optional is more costly. (-)与可为空的参数相比,可选的成本更高。

In general: Optional unifies two states, which have to be unraveled. 一般而言:Optional统一了两个状态,必须将其拆散。 Hence better suited for result than input, for the complexity of the data flow. 因此,对于数据流的复杂性,比输入更适合结果。


#6楼

This advice is a variant of the "be as unspecific as possible regarding inputs and as specific as possible regarding outputs" rule of thumb. 该建议是“对于输入尽可能不具体,而对输出尽可能具体”的一种变体。

Usually if you have a method that takes a plain non-null value, you can map it over the Optional , so the plain version is strictly more unspecific regarding inputs. 通常,如果您有一个采用纯非null值的方法,则可以将其映射到Optional ,因此对于输入,纯格式严格来说更加不确定。 However there are a bunch of possible reasons why you would want to require an Optional argument nonetheless: 但是,仍然有很多可能的原因导致您仍然需要一个Optional参数的原因:

  • you want your function to be used in conjunction with another API that returns an Optional 您希望将您的函数与另一个返回Optional API结合使用
  • Your function should return something other than an empty Optional if the given value is empty 您的函数应返回空值以外的其他值如果给定值为空,则为Optional
  • You think Optional is so awesome that whoever uses your API should be required to learn about it ;-) 您认为Optional非常好,以至于使用API​​的人都必须了解它;-)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章