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

Nei*_*ens 344 java optional java-8

我在许多网站上阅读过Optional只能用作返回类型,而不能在方法参数中使用.我很难找到合乎逻辑的原因.例如,我有一个逻辑,它有2个可选参数.因此,我认为像这样编写我的方法签名是有意义的(解决方案1):

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}
Run Code Online (Sandbox Code Playgroud)

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

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}
Run Code Online (Sandbox Code Playgroud)

或者,我可以用四种公共方法替换我的方法以提供更好的界面并使其更明显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
}
Run Code Online (Sandbox Code Playgroud)

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

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

如果使用解决方案2,则调用代码将如下所示:

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

如果应用解决方案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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Joo*_*gen 171

哦,那些编码风格应该用一些盐.

  1. (+)将Optional结果传递给另一个方法,不进行任何语义分析; 把它留给方法,很好.
  2. ( - )使用在方法中导致条件逻辑的可选参数实际上是相反的.
  3. ( - )需要在Optional中包装一个参数,对于编译器来说是次优的,并且进行了不必要的包装.
  4. ( - )与可空参数相比,可选性更高.

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

  • @biziclop请注意,如果您正在使用`Optional`,那么状态1(`null`可选)通常表示编程错误,因此您也可以不处理它(只是让它抛出`NullPointerException`) (66认同)
  • "对于编译器来说是次优的","与可空参数相比,可选性更高" - 这些参数可能对C语言有效而对Java语言无效.Java程序员应该专注于清晰的代码,可移植性,可测试性,良好的体系结构,模块化等,而不是"可选的是更加昂贵的空引用".如果你发现你需要专注于微优化,那么你最好跳过对象,列表,泛型并切换到数组和原语(我不想在这里冒犯,我只是分享我的观点) . (41认同)
  • 实际上,有一个`Optional`参数代表三种状态之一:一个`​​null`可选,一个非null的`Optional` with`isPresent()== false`和一个非null的`Optional`包装一个实际的值. (32认同)
  • @biziclop是的,一个不可避免的观点已经受到批评.但是_intention_只有非空表达式.没过多久,听到建议在某些情况下避免选择,这是非常具有讽刺意味的.一个`@NotNull Optional`. (15认同)
  • "对于编译器来说是次优的":过早优化是所有邪恶的根源......如果你不编写性能关键代码(在尝试指定一个干净的接口时通常就是这种情况),这应该不是一个问题. (9认同)
  • 我没有得到与编译器相关的意见。所以,如果你用 Java 编程,你就不会为优化而烦恼,这就是你所说的?嗯,前端或典型的 Java 应用程序可能就是这种情况。但是 Java 通常用于关键系统、大数据处理、实时转换等。在这种情况下,您确实需要优化,是的,它对这些系统产生了巨大的影响。如果你只是做一些花哨的界面、前端应用等等,也许你不介意 Joop Eggen 关于编译器的推荐。如果你做更严肃的事情,你确实介意。不要概括整个语言 (4认同)
  • 我开始讨厌Optional。它的大部分用途是完全没有必要的。我还要添加一条准则:仅在值实际上可以为 null 的情况下使用 optional。我已经看到它在 getter 上用于构造函数注入的成员,这些成员是最终的并且不可能为空。在 Optional 出现之前,我看到代码中有很多不必要的空检查。Optional 只会让事情变得更糟。 (3认同)
  • @ Kacper86感谢您声明,因为我主要避免使用null而选择Optional.然而,有一些"干净编码器"显然是为了避免可选作为输入参数的参数,我想列出所有脚踏实地的优点和缺点,**没有判断**.我认为这很重要,因为我们仍然没有多少经验.3.`f(Optional.ofNullable(x))`有点畏缩,但4.确实是"我不需要接地我的电器"的C态度. (2认同)
  • 我认为这个清单并不是真的有用:使用"反作用"这个词并不足以解释这个问题.同样检查null是相同数量的代码,所以我看不出比明显的解决方案更有效.其次,在描述API时,考虑设计中的编译器级优化并不是正确的方法. (2认同)
  • “使用可选参数在方法内部导致条件逻辑实际上是适得其反的。” - 糟糕的论据。map 和 flatMap 是 FP 方式,没有引入条件逻辑。 (2认同)
  • @Mohan 我_确实_喜欢一直使用Optional,尤其是在处理旧代码时。然而,对于问题的上下文来说,这似乎是一个有效的论点,因为使用“int”而不是“Integer”并不是过早的优化。执行 `f(Optional.ofNullable(x))` 有点属于不需要的装箱/拆箱、包装/拆包的 int/Integer 类别。正如我所说,我是可选的忠实粉丝,所以谢谢。 (2认同)

Gil*_*ili 144

我在这个主题上看过的最好的帖子Daniel Olszewski写的:

虽然对于非强制性方法参数可能会考虑将Optional作为诱惑,但与其他可能的替代方案相比,这种解决方案显得苍白无力.为了说明问题,请检查以下构造函数声明:

public SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}
Run Code Online (Sandbox Code Playgroud)

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

SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));
Run Code Online (Sandbox Code Playgroud)

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

当一个方法可以接受可选参数时,最好采用经过充分验证的方法,并使用方法重载设计这种情况.在SystemMessage类的示例中,声明两个单独的构造函数优于使用Optional.

public SystemMessage(String title, String content) {
    this(title, content, null);
}

public SystemMessage(String title, String content, Attachment attachment) {
    // assigning field values
}
Run Code Online (Sandbox Code Playgroud)

这一变化使客户端代码更加简单易读.

SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这种解释没有解决调用者何时解析某些信息可能是可选的问题.使用方法重载(如上所述),调用代码必须说"X是否存在?如果是,我将调用重载方法A.是否存在?我将不得不调用重载方法B.如果X和Y存在,我将不得不调用重载方法C." 等等.对此可能有一个很好的答案,但对"为什么"的这种解释并没有涵盖它. (35认同)
  • 当只有一两段相关时,这就是很多复制+粘贴. (10认同)
  • 此外,在集合方面,空集合和没有集合之间存在明显差异.例如,缓存.这是缓存未命中吗?empty optional/null.是否有缓存命中恰好是一个空集合?完全可选/收藏. (7认同)
  • 当然,你应该_favor_它,但你并不总是能够控制某些代码,而且,在非常真实的意义上,你可能想要区分"有一个值,它是一个空集合"与"没有"价值定义(尚)".由于"魔法空"也是一种沮丧的做法,因此开发人员应该选择最不好的选择.我更喜欢使用空可选来表示缓存未命中而不是空集合,因为实际缓存的值可能是*空集合. (4认同)
  • @Ajax 我认为您误解了这篇文章。他们引用了 [Effective Java](https://www.amazon.ca/Effective-Java-2nd-Joshua-Bloch/dp/0321356683) 一书中提倡的观点,其中说当方法返回类型是 Collection 时(不是缓存会返回的任意对象)那么你应该倾向于返回一个空集合而不是 `null` 或 `Optional`。 (2认同)
  • @Ajax 文章没有异议。您应该赞成返回空集合,除非您有充分的理由不这样做。就您而言,您有充分的理由不这样做。 (2认同)
  • 我只是想知道两个或三个可选参数的方法重载会如何......鲍勃叔叔仍然不会感到自豪。 (2认同)
  • @FranklinYu 静态工厂方法或构建器模式可能适合您的情况。 (2认同)
  • 但是,如果有 2、3 或 4 个可选参数怎么办,这意味着您要多次重载该方法。它可能是 2 ^ #ofParams 变体。 (2认同)

小智 78

几乎没有充分理由不使用Optional参数.反对此的论据依赖于来自权威的论据(参见Brian Goetz - 他的论点是我们不能强制执行非null选项)或者Optional参数可能为null(基本上是相同的参数).当然,Java中的任何引用都可以为null,我们需要鼓励编译器强制执行规则,而不是编程器内存(这是有问题的并且不能扩展).

函数式编程语言鼓励Optional参数.使用此方法的最佳方法之一是使用多个可选参数并使用liftM2函数,假设参数不为空并返回可选参数(请参阅http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/ data/Option.html#liftM2-fj.F-).遗憾的是,Java 8实现了一个支持可选的非常有限的库.

作为Java程序员,我们应该只使用null来与遗留库进行交互.

  • *函数式编程语言鼓励可选参数.*需要引用.大多数功能不应该是可选的; 相反,在存在或不存在值的情况下处理(使用适当的高阶函数)的责任在于所讨论的函数的调用者. (13认同)
  • 这个.实际上,没有一个答案足够令人信服,并且他们都没有回答这个具体问题"为什么使用选项作为方法参数被认为是不好的做法,而使用`@NonNull`注释方法参数如果以不同的方式用于相同的目的则完全没有问题?" 对我来说,只有一个参数至少有一定意义:"可选用于提供具有明确返回类型的更好的API.但是对于方法参数,可以使用重载函数." - 不过,我认为这不是一个足够强大的论据. (5认同)
  • 布莱恩·戈茨的这些评论并不是来自权威的论据。你提供了他的主张的理由...... (5认同)
  • 如何使用来自javax.annotation的`@Nonnull`和`@Nullable`代替?我在我开发的库中广泛使用它们,IDE(IntelliJ)提供的支持非常好. (3认同)
  • 当然,比 null 更好,但更可取的是一开始就不需要很多可选值,因为好的设计:D (3认同)
  • 我发现参数中的可选使代码更难使用,并且实际上增加了引入错误的新方法。任何增加使用复杂性的事情都会更容易出现错误。我们应该避免使用 null 的想法导致了这样的代码: if(Optional.ofNullable(x).isPresent())... 相反 if(x != null)... 所有这一切都增加了冗长并使得错误的可能性更大。(例如,编码员可能会意外地编写 if(Optional.of(x).isPresent())... 这将不起作用。)Optional 对于函数式编程来说是必要且有用的。在其他地方,它们毫无意义。 (2认同)
  • @MiguelMunozOptional.ofNullable(x).isPresent() 是对标准库的无知。从 Java 8 开始,有 Objects.isNull(x) 和 Objects.nonNull(x) (2认同)
  • isNull 和 nonNull 也被添加用于函数式编程,旨在用作 lambda。但我认为在某些情况下它们在函数式编程之外也有意义。竭尽全力避免使用 null 关键字是愚蠢的,但以简单的方式限制其使用是明智的。 (2认同)

Dmi*_*kin 14

也许我会招来一堆反对票和负面评论,但是……我无法忍受。

免责声明:我下面写的并不是对原始问题的真正答案,而是我对这个主题的想法。它的唯一来源是我的想法和我的经验(Java 和其他语言)。

首先让我们检查一下,为什么有人喜欢使用Optional?

对我来说,原因很简单:与其他语言不同,java 没有内置功能来将变量(或类型)定义为可空或不可空。所有“对象”变量都是可为空的,而所有基元类型都不是。为了简单起见,在进一步的讨论中不要考虑基本类型,因此我将简单地声明所有变量都是可为空的。

为什么需要将变量声明为可为空/不可为空?嗯,对我来说,原因是:显式总是比隐式更好。除了显式修饰(例如注释或类型)之外,还可以帮助静态分析器(或编译器)捕获一些与空指针相关的问题。

许多人在上面的评论中争论说,函数不需要有可为空的参数。相反,应该使用重载。但这样的说法只有在教科书中才有用。现实生活中存在不同的情况。考虑类,它代表某些系统的设置,或某些用户的个人数据,或者实际上任何包含大量字段的复合数据结构 - 其中许多字段具有重复的类型,并且某些字段是强制性的,而其他字段是可选的。在这种情况下,继承/构造函数重载并没有真正的帮助。

随机示例:假设我们需要收集有关人员的数据。但有些人不想提供所有数据。当然,这是 POD,所以基本上使用值语义进行类型,所以我希望它或多或少是不可变的(没有设置器)。

class PersonalData {
    private final String name; // mandatory
    private final int age; // mandatory
    private final Address homeAddress; // optional
    private final PhoneNumber phoneNumber; // optional. Dedicated class to handle constraints
    private final BigDecimal income; // optional.
    // ... further fields

    // How many constructor- (or factory-) overloads do we need to handle all cases
    // without nullable arguments? If I am not mistaken, 8. And what if we have more optional
    // fields?

    // ...
}
Run Code Online (Sandbox Code Playgroud)

因此,IMO 上面的讨论表明,尽管大多数情况下我们可以在没有可空参数的情况下生存,但有时这是不可行的。

现在我们来解决这个问题:如果一些参数可以为空,而另一些则不能,我们如何知道是哪一个?

方法 1:所有参数均可为 null(根据 java 标准,基本类型除外)。所以我们检查所有这些。

结果:代码因检查而爆炸,这大多是不需要的,因为正如我们上面讨论的,几乎所有时间我们都可以继续使用可空变量,并且只有在极少数情况下才需要“可为空”。

方法 2:使用文档和/或注释来描述哪些参数/字段可以为空,哪些不能为空。

结果:它并没有真正起作用。人们懒于编写和阅读文档。此外,最近的趋势是,我们应该避免编写文档,而应该让代码本身具有自我描述性。除此之外,所有关于修改代码而忘记修改文档的推理仍然有效。

方法 3:@Nullable @NonNull 等...我个人认为它们很好。但也有一定的缺点:(例如,它们只受到外部工具的尊重,而不是编译器的尊重),最糟糕的是它们不是标准的,这意味着,1.我需要向我的项目添加外部依赖项才能受益2.不同系统对待他们的方式并不统一。据我所知,它们被投票排除在官方 Java 标准之外(我不知道是否有计划再次尝试)。

方法 4:可选<>。其他评论中已经提到了缺点,其中最糟糕的是(IMO)性能损失。它还添加了一些样板,即使我个人发现,使用Optional.empty()和Optional.of()并不是那么糟糕。优点很明显:

  1. 它是 Java 标准的一部分。
  2. 对于代码的读者(或 API 的用户)来说,很明显这些参数可能为空。此外,它强制 API 用户和方法开发人员通过显式包装/展开值来了解这一事实(当使用 @Nullable 等注释时,情况并非如此)。

因此,在我看来,任何方法论(包括这一方法论)都没有非黑即白的界限。我个人最终得出以下准则和约定(仍然不是严格的规则):

  1. 在我自己的代码中,所有变量都必须为非空(但可能为Optional<>)。
  2. 如果我有一个带有一两个可选参数的方法,我会尝试使用重载、继承等重新设计它。
  3. 如果我无法在合理的时间内找到解决方案,我就会开始思考性能是否至关重要(即是否有数百万个对象需要处理)。通常情况并非如此。
  4. 如果没有,我使用可选作为参数类型和/或字段类型。

仍然存在灰色区域,这些约定不起作用:

  • 我们需要高性能(例如处理大量数据,从而使总执行时间非常长,或者吞吐量至关重要的情况)。在这种情况下,Optional 引入的性能损失可能确实是不需要的。
  • 我们处于我们自己编写的代码的边界上,例如:我们从数据库、Rest Endpoint、解析文件等读取。
  • 或者我们只是使用一些外部库,它们不遵循我们的约定,所以再次,我们应该小心......

顺便说一句,最后两种情况也可能是可选字段/参数中需求的来源。即,当数据的结构不是我们自己开发的,而是由一些外部接口、数据库模式等强加的时......

最后,我认为,人们应该思考正在解决的问题,并尝试找到合适的工具。如果Optional<>是合适的,那么我认为没有理由不使用它。

编辑:方法 5:我最近使用了这个,当时我无法使用Optional. 这个想法只是对方法参数和类变量使用命名约定。我使用了“maybe”前缀,这样如果“url”参数可以为空,那么它就变成了maybeUrl。优点是它稍微提高了意图的可理解性(并且没有其他方法的缺点,例如外部依赖性或性能损失)。但也有缺点,例如:没有工具支持此约定(如果您在没有先检查的情况下访问“也许”变量,您的 IDE 不会向您显示任何警告)。另一个问题是,只有参与该项目的所有人员一致应用时,它才会有帮助。


llo*_*giq 11

这个建议是"关于输入尽可能不具体,并且尽可能具体关于输出"的经验法则的变体.

通常,如果您有一个采用普通非空值的方法,则可以将其映射到该方法Optional,因此普通版本在输入方面严格来说是非特定的.然而,尽管如此,仍有许多可能的原因可能需要Optional参数:

  • 您希望您的函数与另一个返回的API一起使用 Optional
  • Optional如果给定值为空,则函数应返回空值以外的其他值
  • 您认为Optional非常棒,无论谁使用您的API都应该被要求了解它;-)


Mik*_*kis 10

所以,如果你允许双关语的话,Oracle 发布了一个预言:

\n
\n

请勿将Optionalbut 用于函数返回值。

\n
\n

\xce\x97ere 是一个不同意见:

\n
\n

您可以null通过Optional 在任何地方使用来完全消除您的代码库:不仅在函数返回值中,而且在函数参数中,在类成员中,在数组成员中,甚至在局部变量中。

\n
\n

我已经在一个 10 万行代码的项目中完成了它。有效。

\n

如果你决定走这条路,那么你就需要彻底,所以你将有很多工作要做。接受的答案中提到的例子Optional.ofNulable()永远不应该发生,因为如果你是彻底的,那么你不应该有null任何地方,因此不需要Optional.ofNullable()

\n

在我上面提到的那个 10 万行代码的项目中,我只在从Optional.ofNullable()我无法控制的外部方法接收结果时使用过几次。我从来没有必要将它们Optional.ofNullable( nullablePointer )作为参数传递给函数,因为我周围没有任何可为空的指针:我总是在它们进入我的系统的几个地方将它们转换为可选值。

\n

现在,如果您决定沿着这条道路走下去,您的解决方案将不会是性能最高的解决方案,因为您将分配大量Optional. 然而:

\n
    \n
  1. 这只不过是运行时性能的劣势。
  2. \n
  3. 虽然缺点是不可忽视的,但也并不严重。
  4. \n
  5. 这是Java的问题,不是你的问题。
  6. \n
\n

让我解释一下最后一点。

\n

Java 不像 C# 那样提供显式的可为空性(自版本 8.0 起),因此它在这方面较差。(我说的是“在这方面”;在其他方面,Java 更好;但现在这是题外话。)

\n

引用类型的显式可为空性的唯一正确替代方案是类型Optional。(而且可以说它甚至稍微好一点,因为Optional如果必须的话,您可以指示可选的可选,而使用显式可空性则不能ReferenceType??,或者至少在当前实现的 C# 中不能。)

\n

Optional不必增加开销,它只在 Java 中这样做。这是因为 Java 也不支持真正的值类型,而 C# 和 Scala 则支持。在这方面,Java 远远不如那些语言。(再次,我说“在这方面”;在其他方面,Java 更好;但现在这是题外话。)如果 Java 确实支持真值类型,那么Optional将被实现为单个机器字,这意味着使用它的运行时开销将为零。

\n

所以,最终归结为一个问题:

\n

您希望代码具有完美的清晰度和类型安全性,还是希望获得最佳性能?

\n

我相信对于高级语言(Java 无疑是其中之一)来说,这个问题很久以前就已经解决了。

\n


Mak*_*oto 8

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

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

public int calculateSomething(@NotNull final String p1, @NotNull final String p2) {}
Run Code Online (Sandbox Code Playgroud)

  • 这里的问题是 @NotNull 不是默认情况,必须明确注释 - 因此,人们由于懒惰而不会做样板文件和东西。 (2认同)
  • 忽略Optional比忽略注释要困难得多,后者是仅在阅读文档/源代码或您的工具可以捕获注释时才会注意到的注释(静态分析不能始终正确确定可空性)。 (2认同)

小智 8

查看JDK10中的JavaDoc,https: //docs.oracle.com/javase/10/docs/api/java/util/Optional.html,增加了一个API说明:

API 注释:Optional 主要用作方法返回类型,其中明确需要表示“无结果”,并且使用 null 可能会导致错误。


dre*_*rew 8

让我们明确一点:在其他语言中,没有反对使用 Maybe 类型作为字段类型、构造函数参数类型、方法参数类型或函数参数类型的一般建议。

因此,如果您“不应该”在 Java 中将 Optional 用作参数类型,则原因特定于 Optional、Java 或两者。

可能适用于其他 Maybe 类型或其他语言的推理在这里可能无效。

根据布赖恩·戈茨Brian Goetz)

[W]e 在添加 [Optional] 时确实有一个明确的意图,它不是一个通用的 Maybe 类型,因为很多人都希望我们这样做。我们的目的是为库方法返回类型提供一种有限的机制,需要一种明确的方式来表示“无结果”,而对这种情况使用 null 极有可能导致错误。

例如,您可能永远不应该将它用于返回结果数组或结果列表的内容;而是返回一个空数组或列表。您几乎不应该将它用作某物的字段或方法参数。

所以答案是针对 Optional 的:它不是“通用的 Maybe 类型”;因此,它是有限的,并且可能以限制其作为字段类型或参数类型的有用性的方式受到限制。

也就是说,在实践中,我很少发现使用 Optional 作为字段类型或参数类型是一个问题。如果 Optional 尽管有其限制,但可以作为您用例的参数类型或字段类型,请使用它。

  • 与所问主题相关的最佳解释之一 (3认同)

Ste*_* B. 6

这对我来说似乎有点傻,但我能想到的唯一原因是方法参数中的对象参数在某种程度上已经是可选的 - 它们可以为null.因此,强迫某人获取现有对象并将其包装在可选对象中是毫无意义的.

话虽这么说,链接方法一起采取/返回选项是一个合理的事情,例如也许monad.

  • 无法返回值和字段也为空?那么`Optional`完全没有意义? (7认同)

Edd*_*ddy 6

我的看法是 Optional 应该是一个 Monad,而这些在 Java 中是不可想象的。

在函数式编程中,您处理纯函数和高阶函数,这些函数仅根据其“业务领域类型”接受和组合其参数。组合以现实世界为基础的函数,或者其计算应该报告给现实世界(所谓的副作用)需要应用程序来自动将值从代表外部世界的 monad 中解包出来(状态、配置、 Futures、Maybe、Either、Writer 等……);这叫做提升。您可以将其视为一种关注点分离。

混合这两个抽象级别不会提高易读性,因此最好避免使用它。


gpi*_*ino 6

接受 Optional 作为参数会导致调用者级别不必要的包装。

例如在以下情况下:

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {}
Run Code Online (Sandbox Code Playgroud)

假设您有两个非空字符串(即从其他方法返回):

String p1 = "p1"; 
String p2 = "p2";
Run Code Online (Sandbox Code Playgroud)

即使您知道它们不是 Empty,您也不得不将它们包装在 Optional 中。

当您必须与其他“可映射”结构组合时,情况会变得更糟,即。要么

Either<Error, String> value = compute().right().map((s) -> calculateSomething(
< here you have to wrap the parameter in a Optional even if you know it's a 
  string >));
Run Code Online (Sandbox Code Playgroud)

参考:

方法不应该期望 Option 作为参数,这几乎总是一种代码味道,表明从调用者到被调用者的控制流泄漏,调用者应该负责检查 Option 的内容

参考 https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749