It’s advertised as The One Nullability Annotation to Rule Them All ™️as if that was the problem to begin with.
JSpecify is supposed to finally put an end to NullPointerExceptions in Java, because sometimes, it’s not obvious to know if a parameter or return value of a method can be null.
The concept is simple, in theory: you only have to put @NullMarked
in all packages (but they are not recursive so be ready to add/update many package-info.java
files), and with that the default becomes not null instead of undefined, then you simply add @Nullable
to all method parameters which are supposed to be null, and all return values, and all fields.
This is all something you could already do decades ago using the dozens of existing Nullable annotations. The IDE will now detect potential missing null checks but also annoy you with all the null checks that you previously added to your code and which can be removed, unless someone is not using the same setup as you because there’s nothing that enforces those null checks at runtime.
Oh wait, but you can use something called NullAway and Errorprone that can be configured to do some static analysis, this will surely work? It does, after some convoluted gradle.build
config modifications (especially on multi modules projects) but… it’s pretty bad at detecting common case like non totally obvious field initializations for example with an initializeIfNeeded()
call in the constructor so you end up adding SuppressWarning("NullAway")
in many places as well as others to disable the code flow analysis of IntelliJ which gets confused too. Then after many changes, you get… not that much. The only somewhat valid NPE case it detected on my project was about sending null strings to JavaFX who does handle those fine anyway (and I know that).
This is clearly not very useful and the reason is:
- all those nullable annotations make you remove useless null checks
- those null checks can still be triggered because there’s nothing enforcing them, other than IDE warnings and some static analyser, if it manages to catch them around all the warning suppression that you added.
Basically those 2 steps above fight against each others. And this will not change until project Valhalla in Java tackles it.
JSpecify is all about potential improvements later on and there’s nothing that guarantees it. People also mention that it’s backed by Google thus it’s not going anywhere but that’s actually a red flag because Google is well known for abandoning projects and changing directions without warnings (I used to be a professional Android developer so I know that well enough).
So what to do? My advice is to keep using Objects.requireNonNull()
and similar in public methods. A static validator can detect them so it’s just as good as putting annotations, and less verbose. In fact, IntelliJ does infer nullability from them already. Also don’t forget to mention when a parameter or return value is nullable in your javadocs (it can also explain how and why it is so).
Don’t bother with nullable annotations.