Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Whats the most elegant way to add two numbers that are Optional<BigDecimal>

I need to perform an add operation on two big decimals that are wrapped optionals:

Optional<BigDecimal> ordersTotal;
Optional<BigDecimal> newOrder;

I want to achieve ordersTotal += newOrder It's important to note that if both values are empty the result should likewise be empty (ie not zero).

Here is what I came up with:

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

but I'm wondering if there's a more elegant solution.

like image 320
maxTrialfire Avatar asked Sep 14 '16 19:09

maxTrialfire


2 Answers

I think the suggested answers of using streams or chains of methods on optionals are very clever, but perhaps so clever as to be obscure. The OP has modeled this as ordersTotal += newOrder with the exception that if both are empty, the result should be empty instead of zero. Maybe it would be reasonable to write the code so that it says that:

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

While this isn't the shortest, it clearly expresses exactly what the OP asked for.

Now I've assigned the computed value to result but the OP actually wanted to assign it back to ordersTotal. If we know both are empty, we can then skip the then-clause that assigns empty to ordersTotal. Doing that, and then inverting the condition gives something simpler:

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

Now, this tends to obscure the both-empty special case, which might not be a good idea. On the other hand, this says "add the values if either is non-empty" which might make a lot of sense for the application.

like image 156
Stuart Marks Avatar answered Oct 19 '22 09:10

Stuart Marks


Not sure if you'll consider it more elegant, but here's one alternative:

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

Another, based on @user140547's suggestion:

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

Note that the first version returns Optional.of(BigDecimal.ZERO) even when both optionals are empty, whereas the second will return Optional.empty() in such a case.

like image 36
shmosel Avatar answered Oct 19 '22 09:10

shmosel