Firstly, there's nothing wrong with explicit null-checks.
Secondly, Optional.ofNullable()
is not meant for validation. By hiding a null-check with it, you're obscuring what the code does and making it harder to read.
Here's a quote from the answer by @StuartMarks, Java and OpenJDK developer, regarding what Optional
is meant to be used for:
The primary use of Optional
is as follows:
Optional is intended to
provide a limited mechanism for library method return types where
there is a clear need to represent "no result," and where using null
for that is overwhelmingly likely to cause errors.
A typical code smell is, instead of the code using method chaining to
handle an Optional returned from some method, it creates an Optional
from something that's nullable, in order to chain methods and avoid
conditionals.
Also have a look at this answer by Stuart Marks "Should Optional.ofNullable() be used for null check?".
Using Optional.ofNullable()
to avoid null-checks is an antipattern. You shouldn't create Optional
in order to validate an object that can be null
I see nothing that can be considered to be "bad" in this snippet from your question. Yes, it's verbose, it's a price for allowing nullable fields.
if (product.getQuantityAvailable() != null && product.getQuantityReserved() != null) {
if (product.getQuantityAvailable() < product.getQuantityReserved()) {
System.out.println("Error");
}
}
If you want to reduce the level of nesting, here's a null-safe alternative with Objects.compare()
:
if (Objects.compare(product.getQuantityAvailable(),
product.getQuantityReserved(),
Comparator.nullsFirst(Comparator.naturalOrder())) < 0) {
// perform the required action
throw new MyCustomException("a message helpful in debuging here");
}
When you have a lot of nullable fields in your objects, which you eventually expect to contain some values, *null-checks are inevitable.
Code clattered with null-checks can be difficult to read, but it doesn't imply that null-checks are the root of all evil. It's just the consequence of your design decisions.
If you want to reduce the number of null-checks in your code, then assign default values (0
for Integer
, BigDecimal.ZERO
, empty collections, etc.) instead of keeping null
references in every place where it doesn't harm the logic of the application.
Sidenote: contrary to some languages like type TypeScript, in Java there's no notion of optional properties, which was initially mentioned in the title of the question. Practices that are suitable for one language aren't necessarily applicable in another. If you want to leverage Java to its full power, reproducing your experience with frontend languages isn't the right way to go.