Venting - Java's Optional
After reading Matt's tip for academic blogging, I decided to hop on tip 4, Vented steam as post, and focus my concerns around the design of Java's Optional type and the capacity for misuse from junior/inexperienced Java engineers. A quick Google search for Optional misuse will render countless results. What many of these articles miss is an illustration of the common bad practices, so as a visual learner myself, I wanted to show in code what happens when you give a baby a knife. These are all examples I've seen used in production and introduced in merge requests by fairly intelligent CS graduates:
1. Null-checking
if (Optional.ofNullable(arg).isPresent()) {
// do the thing...
}
Somehow, we've made null-checking even worse. Stick to the original, it's safe, people know what you're talking about, and it's shorter code to type:
if (arg != null) {
// do the thing
}
2. Arguments
private static String helpfulMethod(Optional<MyClass> arg) {
// do the thing
}
Don't force users to wrap everything in an Optional! The Java language authors have been quite frank that Optional was intended for use strictly as a return type, to convey that a method may or may not return a value. Instead, perform proper validations against your input, like null-checking. If not, you're forcing users to write bad code like below:
MyClass.moreHelpfulMethod(Optional.of(val0), Optional.of(val1), Optional.of(val2));
or worse...
MyClass.moreHelpfulMethod(Optional.ofNullable(val0), Optional.ofNullable(val1), Optional.ofNullable(val2));
As the author of said function, using Optional arguments forces you to check against three cases: null, non-null-without-value, and non-null-with-value, instead of two: null or a valid value.
3. Method Chaining
Optional.ofNullable(val).orElse(() -> new Value()).ifPresent(myClassInstance::setValue);
Again, stick to the fundamentals:
if (val == null) {
val = new Value(); // Or throw an exception/error
}
myClassInstance.setValue(val);
I'm not going to start posting memory graphs on here, but resources claim that wrapping references in Optional will incur a 4x memory and GC overhead.
4. Returning Null
public Optional<MyClass> extremelyHelpfulMethod(String arg) {
//...do the thing
return null;
}
Let's hope no one decides to chain to that method.
5. If Present. Get.
if (myOptional.isPresent()) {
var myValue = myOptional.get();
}
This one is a little bit trickier, and I always see it in production and in merge requests, but I don't tend to get as tufted (or not as tufted as Brian Goetz). Logically, it makes sense; you're doing the due diligence to check if your value is present, and if so, you retrieve it. Instead, understand your domain, and decide when it is best to return a default value or throw an exception:
var val = extremelyHelpfulMethod(arg).orElseThrow(() -> new FieldNotFound());
Conclusion
Avoid these bad practices, and if you want a great talk on how to use Java's Optional properly, watch Stuart Mark's presentation.