添加两个可选数字的最优雅方法是什么<BigDecimal>
Whats the most elegant way to add two numbers that are Optional<BigDecimal>
我需要对包裹可选值的两个大小数执行加法运算:
Optional<BigDecimal> ordersTotal;
Optional<BigDecimal> newOrder;
我要实现ordersTotal += newOrder
重要的是要注意,如果两个值都为空,则结果同样应该为空(即不为零)。
这是我想出的:
ordersTotal = ordersTotal.flatMap( b -> Optional.of(b.add(newOrder.orElse(BigDecimal.ZERO))));
但我想知道是否有更优雅的解决方案。
您可以使用可选的流。然后你可以做一个bigdecimals的流,然后减少那些bigdecimals,否则return 0.
这样做的好处是,如果您想执行两个以上的可选操作,则不必更改代码。
(如果需要可以稍后添加代码,目前我没有访问计算机)
不确定您是否会认为它更优雅,但这里有一个替代方案:
ordersTotal = Optional.of(ordersTotal.orElse(BigDecimal.ZERO).add(newOrder.orElse(BigDecimal.ZERO)));
另一个,基于:
ordersTotal = Stream.of(ordersTotal, newOrder)
.filter(Optional::isPresent)
.map(Optional::get)
.reduce(BigDecimal::add);
请注意,第一个版本 returns Optional.of(BigDecimal.ZERO)
即使两个选项都为空,而第二个版本 return Optional.empty()
在这种情况下。
此处的 Optional 和 Stream 不能很好地组合在一起。
java8 中最好的是:
ordersTotaI = !ordersTotaI.isPresent() ? newOrder
: !newOrder.isPresent() ? ordersTotaI
: Optional.of(ordersTotaI.get().add(newOrder.get()));
不过,好消息是,java 9 将为 Optional 添加一些不错(也很丑陋)的功能。
请注意您的解决方案
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);
我认为在可选项上使用流或方法链的建议答案非常聪明,但也许聪明到晦涩难懂。 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)));
}
现在,这往往会掩盖双空的特殊情况,这可能不是一个好主意。另一方面,这表示 "add the values if either is non-empty" 这对应用程序可能很有意义。
错的是你的需求不是你的解决方案。一个空的 Optional 不是零而是一个缺失值。你基本上是在问 5 + NaN 等于 5。Optional 的 flatMap 引导你走上快乐的道路:5 + Nan 是 Nan 而这正是 flatMap 所做的。
我知道这是一个旧线程,但是这个怎么样?
orderTotal = !newOrder.isPresent()?
orderTotal :
newOrder.flatMap(v -> Optional.of(v.add(orderTotal.orElse(BigDecimal.ZERO));
我对这种方法的想法是这样的:
所有闪亮的 Optional 等背后的基本逻辑仍然是
orderTotal += newOrder
在第一个newOrder存在之前orderTotal不存在,在代码中用一个空的Optional表示。
- 如果newOrder还不存在(又是一个空的Optional),则根本不需要任何操作,即不需要修改orderTotal
- 如果有 newOrder,调用其 flatMap(..),如 maxTrialfire 的原始 post.
中所示
考虑到您要重新分配给 ordersTotal
,您会注意到 ordersTotal
仅在出现 newOrder
时才会更改。
因此您可以从该检查开始,并将其写为:
if (newOrder.isPresent()) {
ordersTotal = newOrder.map(ordersTotal.orElse(ZERO)::add);
}
(这可以被认为是 的简化。这也是方法引用无法转换回 lambda 的情况,因为 ordersTotal
不是实际上是最终的)
如果你从这个检查开始,还有另一种可能的“聪明”方法:
if (newOrder.isPresent()) {
ordersTotal = ordersTotal.map(o -> newOrder.map(o::add)).orElse(newOrder);
}
其中中间 map()
returns 一个 Optional<Optional<BigDecimal>>
其内部 Optional
不能为空。由于可读性差,我认为它不是一个好的解决方案,因此我会推荐第一个选项或 Stuart 的解决方案之一。
我需要对包裹可选值的两个大小数执行加法运算:
Optional<BigDecimal> ordersTotal;
Optional<BigDecimal> newOrder;
我要实现ordersTotal += newOrder 重要的是要注意,如果两个值都为空,则结果同样应该为空(即不为零)。
这是我想出的:
ordersTotal = ordersTotal.flatMap( b -> Optional.of(b.add(newOrder.orElse(BigDecimal.ZERO))));
但我想知道是否有更优雅的解决方案。
您可以使用可选的流。然后你可以做一个bigdecimals的流,然后减少那些bigdecimals,否则return 0.
这样做的好处是,如果您想执行两个以上的可选操作,则不必更改代码。
(如果需要可以稍后添加代码,目前我没有访问计算机)
不确定您是否会认为它更优雅,但这里有一个替代方案:
ordersTotal = Optional.of(ordersTotal.orElse(BigDecimal.ZERO).add(newOrder.orElse(BigDecimal.ZERO)));
另一个,基于
ordersTotal = Stream.of(ordersTotal, newOrder)
.filter(Optional::isPresent)
.map(Optional::get)
.reduce(BigDecimal::add);
请注意,第一个版本 returns Optional.of(BigDecimal.ZERO)
即使两个选项都为空,而第二个版本 return Optional.empty()
在这种情况下。
此处的 Optional 和 Stream 不能很好地组合在一起。
java8 中最好的是:
ordersTotaI = !ordersTotaI.isPresent() ? newOrder
: !newOrder.isPresent() ? ordersTotaI
: Optional.of(ordersTotaI.get().add(newOrder.get()));
不过,好消息是,java 9 将为 Optional 添加一些不错(也很丑陋)的功能。
请注意您的解决方案
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);
我认为在可选项上使用流或方法链的建议答案非常聪明,但也许聪明到晦涩难懂。 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)));
}
现在,这往往会掩盖双空的特殊情况,这可能不是一个好主意。另一方面,这表示 "add the values if either is non-empty" 这对应用程序可能很有意义。
错的是你的需求不是你的解决方案。一个空的 Optional 不是零而是一个缺失值。你基本上是在问 5 + NaN 等于 5。Optional 的 flatMap 引导你走上快乐的道路:5 + Nan 是 Nan 而这正是 flatMap 所做的。
我知道这是一个旧线程,但是这个怎么样?
orderTotal = !newOrder.isPresent()?
orderTotal :
newOrder.flatMap(v -> Optional.of(v.add(orderTotal.orElse(BigDecimal.ZERO));
我对这种方法的想法是这样的:
所有闪亮的 Optional 等背后的基本逻辑仍然是
orderTotal += newOrder在第一个newOrder存在之前orderTotal不存在,在代码中用一个空的Optional表示。
- 如果newOrder还不存在(又是一个空的Optional),则根本不需要任何操作,即不需要修改orderTotal
- 如果有 newOrder,调用其 flatMap(..),如 maxTrialfire 的原始 post. 中所示
考虑到您要重新分配给 ordersTotal
,您会注意到 ordersTotal
仅在出现 newOrder
时才会更改。
因此您可以从该检查开始,并将其写为:
if (newOrder.isPresent()) {
ordersTotal = newOrder.map(ordersTotal.orElse(ZERO)::add);
}
(这可以被认为是 ordersTotal
不是实际上是最终的)
如果你从这个检查开始,还有另一种可能的“聪明”方法:
if (newOrder.isPresent()) {
ordersTotal = ordersTotal.map(o -> newOrder.map(o::add)).orElse(newOrder);
}
其中中间 map()
returns 一个 Optional<Optional<BigDecimal>>
其内部 Optional
不能为空。由于可读性差,我认为它不是一个好的解决方案,因此我会推荐第一个选项或 Stuart 的解决方案之一。