I\'m looking to make my code more readable as well as use tooling like IDE code inspection and/or static code analysis (FindBugs and Sonar) to avoid NullPointerExceptions.
Doesn't sun have their own now? What's this:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
This seems to be packaged with all the versions of Java I've used within the last few years.
Edit: As mentioned in the comments below, you probably don't want to use these. In that case, my vote is for the IntelliJ jetbrains annotations!
Distinguish between static analysis and runtime analysis. Use static analysis for internal stuff, and runtime analysis for the public boundaries of your code.
For things that should not be null:
Runtime check: Use "if (x == null) ..." (zero dependency) or @javax.validation.NotNull (with bean validation) or @lombok.NonNull (plain and simple) or guavas Preconditions.checkNotNull(...)
Static check: Use an @NonNull annotation
This should give the best result: warnings in the IDE, errors by Findbugs and checkerframework, meaningful runtime exceptions.
Do not expect static checks to be mature, their naming is not standardized and different libraries and IDEs treat them differently, ignore them. The JSR305 javax.annotations.* classes look like standard, but they are not, and they cause split packages with Java9+.
Some notes explanations:
Before Java9, this is my recommendation:
// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;
// file: PublicApi
package example;
public interface PublicApi {
Person createPerson(
// NonNull by default due to package-info.java above
String firstname,
String lastname);
}
// file: PublicApiImpl
public class PublicApiImpl implements PublicApi {
public Person createPerson(
// In Impl, handle cases where library users still pass null
@Nullable String firstname, // Users might send null
@Nullable String lastname // Users might send null
) {
if (firstname == null) throw new IllagalArgumentException(...);
if (lastname == null) throw new IllagalArgumentException(...);
return doCreatePerson(fistname, lastname, nickname);
}
@NonNull // Spotbugs checks that method cannot return null
private Person doCreatePerson(
String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
String lastname,
@Nullable String nickname // tell Spotbugs null is ok
) {
return new Person(firstname, lastname, nickname);
}
@CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
private Person getNickname(
String firstname,
String lastname) {
return NICKNAMES.get(firstname + ':' + lastname);
}
}
Note that there is no way to make Spotbugs raise a warning when a nullable method parameter is dereferenced (at the time of writing, version 3.1 of Spotbugs). Maybe checkerframework can do that.
Sadly these annotations do not distinguish between the cases of a public method of a library with arbitrary callsites, and non-public methods where each callsite can be known. So the double meaning of: "Indicate that null is undesired, but prepare for null being passed nevertheless" is not possible in a single declaration, hence the above example has different annotations for the interface and the implementation.
For cases where the split interface approach is not practical, the following approach is a compromise:
public Person createPerson(
@NonNull String firstname,
@NonNull String lastname
) {
// even though parameters annotated as NonNull, library clients might call with null.
if (firstname == null) throw new IllagalArgumentException(...);
if (lastname == null) throw new IllagalArgumentException(...);
return doCreatePerson(fistname, lastname, nickname);
}
This helps clients to not pass null (writing correct code), while returning useful errors if they do.
If you are working on a big project, you may be better of creating your own @Nullable
and/or @NotNull
annotations.
For example:
@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD,
java.lang.annotation.ElementType.METHOD,
java.lang.annotation.ElementType.PARAMETER,
java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable
{
}
If you use the correct retention policy, then the annotations won't be available at runtime. From that point of view, it is just an internal thing.
Even though this is not a strict science, I think it makes most sense to use an internal class for it.
@Nullable
/@NotNull
annotations.How to configure this in IntelliJ ?
Click the "police officer" in the lower right corner of the IntelliJ status bar. And click "Configure inspections" in the popup. Next ...
Unfortunately, JSR 308
will not add more values than this project local Not Null suggestion here
Java 8
will not come with a single default annotation or its own Checker
framework.
Similar to Find-bugs or JSR 305
, this JSR is poorly maintained by a small bunch of mostly academic teams.
No commercial power behind it, thus JSR 308
launches EDR 3
(Early Draft Review at JCP
) NOW, while Java 8
is supposed to ship in less than 6 months:-O
Similar to 310
btw. but unlike 308 Oracle
has taken charge of that now away from its founders to minimize harm it'll do to the Java Platform.
Every project, vendor and academic class like the ones behind the Checker Framework
and JSR 308
will create its own proprietary checker annotation.
Making source code incompatible for years to come, until a few popular compromises could be found and maybe added to Java 9
or 10
, or via frameworks like Apache Commons
or Google Guava
;-)
If you're developing for android, you're somewhat tied to Eclipse (edit: at time of writing, not anymore), which has its own annotations. It's included in Eclipse 3.8+ (Juno), but disabled by default.
You can enable it at Preferences > Java > Compiler > Errors/Warnings > Null analysis (collapsable section at the bottom).
Check "Enable annotation-based null analysis"
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage has recommendations on settings. However, if you have external projects in your workspace (like the facebook SDK), they may not satisfy those recommendations, and you probably don't want to fix them with each SDK update ;-)
I use:
This answer is Android specific. Android has support package called support-annotations
. This provides dozens of Android specific annotations and also provides common ones like NonNull
, Nullable
etc.
To add support-annotations package, add the following dependency in your build.gradle:
compile 'com.android.support:support-annotations:23.1.1'
and then use:
import android.support.annotation.NonNull;
void foobar(@NonNull Foo bar) {}