Is there a BigDecimal library with the basic operations of BigDecimal which allows null values?
Null should be treated as 0 for mathematical purpose.
I don't want to do all the null checks for possible null values.
You either never allow null values in database, application or view and initialize everything with new BigDecimal(0) or perform null checks on every usage for nullable values.
Something like:
public static BigDecimal add(final BigDecimal value, final BigDecimal augend)
{
if (value == null)
return augend;
else if (augend == null)
return value;
else
return value.add(augend);
}
public static BigDecimal multiply(final BigDecimal value, final BigDecimal multiplicand)
{
if (value == null || multiplicand == null)
return null;
return value.multiply(multiplicand);
}
5 Answers
Save the coding, just don't allow null values in the database. Make the default value zero.
As for new BigDecimal(0): no, use BigDecimal.ZERO.
I had a similar problem (not related to a database though, just needed to sum up a couple of nullable BigDecimals). Did not find any library, so had to write the following function myself:
public static BigDecimal add(BigDecimal... addends) {
BigDecimal sum = BigDecimal.ZERO;
if (addends != null) {
for (BigDecimal addend : addends) {
if (addend == null) {
addend = BigDecimal.ZERO;
}
sum = sum.add(addend);
}
}
return sum;
}
The same in Java 8:
public static BigDecimal add(BigDecimal... addends) {
if (addends == null) {
return BigDecimal.ZERO;
}
return Arrays.stream(addends)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
I guess I don't see the point of the library checking for null. Sure, the library won't throw a NPE, but the caller is eventually going to have to check for it. What is the caller of your above multiply going to do? It can't just use the output. It's going to have to check to see if the returned value is null at some point before it can do anything with the value.
Also, for any application I've ever written, a null is much different than zero. I wouldn't want to use one that treated a null as zero.
If your requirement is that nulls aren't allowed in your DB, I would check for nulls in your DAO layer before writing to the DB.
If the list contains null elements, it doesn't equals null... So here is a unit test that test all the cases and its implementation :
@ParameterizedTest
@MethodSource("shouldSumBigDecimalsParams")
void shouldSumBigDecimals(BigDecimal expectedSum, BigDecimal first, BigDecimal second) {
BigDecimal sum = bigDecimalsSum(first, second);
assertThat(sum).isEqualTo(expectedSum);
}
private static Stream<Arguments> shouldSumBigDecimalsParams() {
return Stream.of(
Arguments.of(new BigDecimal("1010"), new BigDecimal("1000"), BigDecimal.TEN),
Arguments.of(new BigDecimal("1000"), new BigDecimal("1000"), null),
Arguments.of(BigDecimal.TEN, null, BigDecimal.TEN),
Arguments.of(BigDecimal.ZERO, null, BigDecimal.ZERO),
Arguments.of(BigDecimal.ZERO, BigDecimal.ZERO, null),
Arguments.of(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO),
Arguments.of(null, null, null)
);
}
The implementation :
static BigDecimal bigDecimalsSum(BigDecimal... bigdecimals) {
if (Arrays.stream(bigdecimals).allMatch(Objects::isNull)) {
return null;
}
return Arrays.stream(bigdecimals)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
You can have a look on this library:
It can handle every number (BigDecimal, Double, custom types, ...) and handles null values as zero.