什么是最优雅的方式来添加两个可选的数字

我需要对包含选项的两个大小数执行添加操作:

Optional ordersTotal; Optional newOrder; 

我想实现ordersTotal + = newOrder重要的是要注意,如果两个值都为空,则结果同样应为空(即不为零)。

这是我想出的:

 ordersTotal = ordersTotal.flatMap( b -> Optional.of(b.add(newOrder.orElse(BigDecimal.ZERO)))); 

但我想知道是否有一个更优雅的解决方案。

不确定你是否会认为它更优雅,但这里有一个替代方案:

 ordersTotal = Optional.of(ordersTotal.orElse(BigDecimal.ZERO).add(newOrder.orElse(BigDecimal.ZERO))); 

另一个,基于@ user140547的建议 :

 ordersTotal = Stream.of(ordersTotal, newOrder) .filter(Optional::isPresent) .map(Optional::get) .reduce(BigDecimal::add); 

请注意,即使两个选项都为空,第一个版本也会返回Optional.of(BigDecimal.ZERO) ,而在这种情况下,第二个版本将返回Optional.empty()

我认为在选项上使用流或方法链的建议答案非常聪明,但也许是如此模糊以至于模糊不清。 OP已将其建模为ordersTotal += newOrder ,但如果两者都为空,则结果应为空而不是零。 也许编写代码是合理的,因此它说:

  if (!ordersTotal.isPresent() && !newOrder.isPresent()) { result = Optional.empty(); } else { result = Optional.of(ordersTotal.orElse(ZERO).add(newOrder.orElse(ZERO))); } 

虽然这不是最短的,但它清楚地表达了OP所要求的内容。

现在我已将计算值分配给result但OP实际上想将其分配回ordersTotal 。 如果我们都知道两者都是空的,那么我们就可以跳过为ordersTotal分配空的then子句。 这样做,然后反转条件给出了一些更简单的方法:

  if (ordersTotal.isPresent() || newOrder.isPresent()) { ordersTotal = Optional.of(ordersTotal.orElse(ZERO).add(newOrder.orElse(ZERO))); } 

现在,这往往会掩盖两个空的特殊情况,这可能不是一个好主意。 另一方面,这表示“如果其中任何一个非空,则添加值”,这可能对应用程序有很大意义。

您可以使用选项流。 然后你可以创建一个bigdecimals流,然后减少那些bigdecimals,否则返回0。

这样做的好处是,如果您想要执行两个以上的选项,则无需更改代码。

(如果需要,可以在以后添加代码,目前我无法访问计算机)

请注意您的解决方案

 ordersTotal=ordersTotal.flatMap(b -> Optional.of(b.add(newOrder.orElse(BigDecimal.ZERO)))); 

如果ordersTotal为空,则生成一个空的Optional ,即使newOrder不是。

这可以通过将其更改为来修复

 ordersTotal=ordersTotal .map(b -> Optional.of(b.add(newOrder.orElse(BigDecimal.ZERO)))) .orElse(newOrder); 

但我更喜欢

 ordersTotal=ordersTotal .map(b -> newOrder.map(b::add).orElse(b)) .map(Optional::of).orElse(newOrder); 

我知道这是一个老线程,但是这个怎么样?

 orderTotal = !newOrder.isPresent()? orderTotal : newOrder.flatMap(v -> Optional.of(v.add(orderTotal.orElse(BigDecimal.ZERO)); 

我这种方法背后的想法是这样的:

  • 在所有灵魂可选等的背后,这里的基本逻辑仍然存在
    orderTotal + = newOrder

  • 在第一个newOrder存在之前,orderTotal不存在,这在代码中由空的Optional表示。

  • 如果newOrder还不存在(另一个空的Optional),则根本不需要操作,即不需要修改orderTotal
  • 如果有newOrder,则调用maxTrialfire原始post中显示的flatMap(..)。

这里的Optional和Stream不能优雅地融合在一起。

java 8中最好的是:

 ordersTotaI = !ordersTotaI.isPresent() ? newOrder : !newOrder.isPresent() ? ordersTotaI : Optional.of(ordersTotaI.get().add(newOrder.get())); 

然而,好消息是,java 9将为Optional添加一些不错(也很难看)的function。

有什么不对,你的要求不是你的解决方案。 空的Optional不是零,而是缺少值。 你基本上要求5 + NaN等于5.可选的flatMap引导你走向快乐的道路:5 + Nan是Nan,这正是flatMap的作用。

考虑到您要重新分配到ordersTotal ,您会注意到如果newOrder存在, ordersTotal只会更改。

因此,您可以从该检查开始,并将其写为:

 if (newOrder.isPresent()) { ordersTotal = newOrder.map(ordersTotal.orElse(ZERO)::add); } 

(这可以被视为Stuart Marks的第二个解决方案的简化。这也是由于ordersTotal无法有效最终,方法引用无法转换回lambda的情况)

如果你从这个检查开始,还有另一种可能的“ 聪明 ”方法:

 if (newOrder.isPresent()) { ordersTotal = ordersTotal.map(o -> newOrder.map(o::add)).orElse(newOrder); } 

其中,中间map()返回一个Optional>其内部Optional不能为空。 由于其可读性差,我不认为这是一个很好的解决方案,因此我建议使用第一个选项或Stuart的解决方案。