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. Many of the tools seem incompatible with each others' @NotNull
/@NonNull
/@Nonnull
annotation and listing all of them in my code would be terrible to read. Any suggestions of which one is the 'best'? Here is the list of equivalent annotations I've found:
javax.validation.constraints.NotNull Created for runtime validation, not static analysis. documentation
edu.umd.cs.findbugs.annotations.NonNull Used by FindBugs (dead project) and its successor SpotBugs static analysis and therefore Sonar (now Sonarqube) FindBugs documentation, SpotBugs documentation
javax.annotation.Nonnull This might work with FindBugs too, but JSR-305 is inactive. (See also: What is the status of JSR 305?) source
org.jetbrains.annotations.NotNull Used by IntelliJ IDEA IDE for static analysis. documentation
lombok.NonNull Used to control code generation in Project Lombok. Placeholder annotation since there is no standard. source, documentation
androidx.annotation.NonNull Marker annotation available in Android, provided by annotation package documentation
org.eclipse.jdt.annotation.NonNull Used by Eclipse for static code analysis documentation
com.sun.istack.internal.NotNull
. OMG...
Since JSR 305 (whose goal was to standardize @NonNull
and @Nullable
) has been dormant for several years, I'm afraid there is no good answer. All we can do is to find a pragmatic solution and mine is as follows:
Syntax
From a purely stylistic standpoint I would like to avoid any reference to IDE, framework or any toolkit except Java itself.
This rules out:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
Which leaves us with either javax.validation.constraints
or javax.annotation
. The former comes with JEE. If this is better than javax.annotation
, which might come eventually with JSE or never at all, is a matter of debate. I personally prefer javax.annotation
because I wouldn't like the JEE dependency.
This leaves us with
javax.annotation
which is also the shortest one.
There is only one syntax which would even be better: java.annotation.Nullable
. As other packages graduated from javax
to java
in the past, the javax.annotation would be a step in the right direction.
Implementation
I was hoping that they all have basically the same trivial implementation, but a detailed analysis showed that this is not true.
First for the similarities:
The @NonNull
annotations all have the line
public @interface NonNull {}
except for
org.jetbrains.annotations which calls it @NotNull and has a trivial implementation
javax.annotation which has a longer implementation
javax.validation.constraints which also calls it @NotNull and has an implementation
The @Nullable
annotations all have the line
public @interface Nullable {}
except for (again) the org.jetbrains.annotations
with their trivial implementation.
For the differences:
A striking one is that
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
all have runtime annotations (@Retention(RUNTIME)
), while
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
are only compile time (@Retention(CLASS)
).
As described in this SO answer the impact of runtime annotations is smaller than one might think, but they have the benefit of enabling tools to do runtime checks in addition to the compile time ones.
Another important difference is where in the code the annotations can be used. There are two different approaches. Some packages use JLS 9.6.4.1 style contexts. The following table gives an overview:
Package FIELD METHOD PARAMETER LOCAL_VARIABLE android.support.annotation ✔️ ✔️ ✔️ edu.umd.cs.findbugs.annotations ✔️ ✔️ ✔️ ✔️ org.jetbrains.annotation ✔️ ✔️ ✔️ ✔️ lombok ✔️ ✔️ ✔️ ✔️ javax.validation.constraints ✔️ ✔️ ✔️
org.eclipse.jdt.annotation
, javax.annotation
and org.checkerframework.checker.nullness.qual
use the contexts defined in JLS 4.11, which is in my opinion the right way to do it.
This leaves us with
javax.annotation
org.checkerframework.checker.nullness.qual
in this round.
Code
To help you to compare further details yourself I list the code of every annotation below. To make comparison easier I removed comments, imports and the @Documented
annotation. (they all had @Documented
except for the classes from the Android package). I reordered the lines and @Target
fields and normalized the qualifications.
package android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}
package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}
package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}
package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}
package javax.annotation;
@TypeQualifier
@Retention(RUNTIME)
public @interface Nonnull {
When when() default When.ALWAYS;
static class Checker implements TypeQualifierValidator<Nonnull> {
public When forConstantValue(Nonnull qualifierqualifierArgument,
Object value) {
if (value == null)
return When.NEVER;
return When.ALWAYS;
}
}
}
package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf(MonotonicNonNull.class)
@ImplicitFor(
types = {
TypeKind.PACKAGE,
TypeKind.INT,
TypeKind.BOOLEAN,
TypeKind.CHAR,
TypeKind.DOUBLE,
TypeKind.FLOAT,
TypeKind.LONG,
TypeKind.SHORT,
TypeKind.BYTE
},
literals = {LiteralKind.STRING}
)
@DefaultQualifierInHierarchy
@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
@DefaultInUncheckedCodeFor({TypeUseLocation.PARAMETER, TypeUseLocation.LOWER_BOUND})
public @interface NonNull {}
For completeness, here are the @Nullable
implementations:
package android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}
package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}
package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}
package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}
package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}
package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf({})
@ImplicitFor(
literals = {LiteralKind.NULL},
typeNames = {java.lang.Void.class}
)
@DefaultInUncheckedCodeFor({TypeUseLocation.RETURN, TypeUseLocation.UPPER_BOUND})
public @interface Nullable {}
The following two packages have no @Nullable
, so I list them separately; Lombok has a pretty boring @NonNull
. In javax.validation.constraints
the @NonNull
is actually a @NotNull
and it has a longish implementation.
package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}
package javax.validation.constraints;
@Retention(RUNTIME)
@Target({ FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Constraint(validatedBy = {})
public @interface NotNull {
String message() default "{javax.validation.constraints.NotNull.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default {};
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@interface List {
NotNull[] value();
}
}
Support
From my experience, javax.annotation
is at least supported by Eclipse and the Checker Framework out of the box.
Summary
My ideal annotation would be the java.annotation
syntax with the Checker Framework implementation.
If you don't intend to use the Checker Framework the javax.annotation
(JSR-305) is still your best bet for the time being.
If you are willing to buy into the Checker Framework just use their org.checkerframework.checker.nullness.qual
.
Sources
android.support.annotation from android-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations from findbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation from org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations from jetbrains-annotations-13.0.jar
javax.annotation from gwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual from checker-framework-2.1.9.zip
lombok from lombok commit f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints from validation-api-1.0.0.GA-sources.jar
I very much like the Checker Framework, which is an implementation of type annotations (JSR-308) which is used to implement defect checkers like a nullness checker. I haven't really tried any others to offer any comparison, but I've been happy with this implementation.
I'm not affiliated with the group that offers the software, but I am a fan.
Four things I like about this system:
It has a defect checkers for nullness (@Nullable), but also has ones for immutability and interning (and others). I use the first one (nullness) and I'm trying to get into using the second one (immutability/IGJ). I'm trying out the third one, but I'm not certain about using it long term yet. I'm not convinced of the general usefulness of the other checkers yet, but its nice to know that the framework itself is a system for implementing a variety of additional annotations and checkers. The default setting for nullness checking works well: Non-null except locals (NNEL). Basically this means that by default the checker treats everyhing (instance variables, method parameters, generic types, etc) except local variables as if they have a @NonNull type by default. Per the documentation: The NNEL default leads to the smallest number of explicit annotations in your code. You can set a different default for a class or for a method if NNEL doesn't work for you. This framework allows you to use with without creating a dependency on the framework by enclosing your annotations in a comment: e.g. /*@Nullable*/. This is nice because you can annotate and check a library or shared code, but still be able to use that library/shared coded in another project that doesn't use the framework. This is a nice feature. I've grown accustom to using it, even though I tend to enable the Checker Framework on all my projects now. The framework has a way to annotate APIs you use that aren't already annotated for nullness by using stub files.
I use the IntelliJ one, because I'm mostly concerned with IntelliJ flagging things that might produce a NPE. I agree that it's frustrating not having a standard annotation in the JDK. There's talk of adding it, it might make it into Java 7. In which case there will be one more to choose from!
javax.annotation.Nonnull
is more widely accepted, isn't it?
According to the Java 7 features list JSR-308 type annotations are deferred to Java 8. JSR-305 annotations are not even mentioned.
There is a bit of info on the state of JSR-305 in an appendix of the latest JSR-308 draft. This includes the observation that JSR-305 annotations seem to be abandoned. The JSR-305 page also shows it as "inactive".
In the mean time, the pragmatic answer is to use the annotation types that are supported by the most widely used tools ... and be prepared to change them if the situation changes.
In fact, JSR-308 does not define any annotation types/classes, and it looks like they think it is out of scope. (And they are right, given the existence of JSR-305).
However, if JSR-308 really looks like making it into Java 8, it wouldn't surprise me if interest in JSR-305 revived. AFAIK, the JSR-305 team hasn't formally abandoned their work. They have just been quiet for 2+ years.
It is interesting that Bill Pugh (the tech lead for JSR-305) is one of the guy behind FindBugs.
For Android projects you should use android.support.annotation.NonNull
and android.support.annotation.Nullable
. These and other helpful Android-specific annotations are available in the Support Library.
From http://tools.android.com/tech-docs/support-annotations:
The support library itself has also been annotated with these annotations, so as a user of the support library, Android Studio will already check your code and flag potential problems based on these annotations.
javax.annotation.*
annotations also
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(...) Use Optional for method return types (only). Either Java8 or Guava.
Use Optional for method return types (only). Either Java8 or Guava.
Static check: Use an @NonNull annotation
Where it fits, use @...NonnullByDefault annotations on class or package level. Create these annotations yourself (examples are easy to find). Else, use @...CheckForNull on method returns to avoid NPEs
Else, use @...CheckForNull on method returns to avoid NPEs
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:
Findbugs/spotbugs/jsr305 annotations with package javax.validation.* clash with other modules in Java9+, also possibly violate Oracle license
Spotbugs annotations still depends on jsr305/findbugs annotations at compiletime (at the time of writing https://github.com/spotbugs/spotbugs/issues/421)
jetbrains @NotNull name conflicts with @javax.validation.NotNull.
jetbrains, eclipse or checkersframework annotations for static checking have the advantage over javax.annotations that they do not clash with other modules in Java9 and higher
@javax.annotations.Nullable does not mean to Findbugs/Spotbugs what you (or your IDE) think it means. Findbugs will ignore it (on members). Sad, but true (https://sourceforge.net/p/findbugs/bugs/1181)
For static checking outside an IDE, 2 free tools exist: Spotbugs(formerly Findbugs) and checkersframework.
The Eclipse library has @NonNullByDefault, jsr305 only has @ParametersAreNonnullByDefault. Those are mere convenience wrappers applying base annotations to everything in a package (or class), you can easily create your own. This can be used on package. This may conflict with generated code (e.g. lombok).
Using lombok as an exported dependency should be avoided for libraries that you share with other people, the less transitive dependencies, the better
Using Bean validation framework is powerful, but requires high overhead, so that's overkill just to avoid manual null checking.
Using Optional for fields and method parameters is controversial (you can find articles about it easily)
Android null annotations are part of the Android support library, they come with a whole lot of other classes, and don't play nicely with other annotations/tools
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 anyone is just looking for the IntelliJ classes: you can get them from the maven repository with
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>15.0</version>
</dependency>
JSR305 and FindBugs are authored by the same person. Both are poorly maintained but are as standard as it gets and are supported by all major IDEs. The good news is that they work well as-is.
Here is how to apply @Nonnull to all classes, methods and fields by default. See https://stackoverflow.com/a/13319541/14731 and https://stackoverflow.com/a/9256595/14731
Define @NotNullByDefault
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
/**
* This annotation can be applied to a package, class or method to indicate that the class fields,
* method return types and parameters in that element are not null by default unless there is: <ul>
* <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
* case the annotation of the corresponding parameter in the superclass applies) <li> there is a
* default parameter annotation applied to a more tightly nested element. </ul>
* <p/>
* @see https://stackoverflow.com/a/9256595/14731
*/
@Documented
@Nonnull
@TypeQualifierDefault(
{
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.LOCAL_VARIABLE,
ElementType.METHOD,
ElementType.PACKAGE,
ElementType.PARAMETER,
ElementType.TYPE
})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNullByDefault
{
}
2. Add the annotation to each package: package-info.java
@NotNullByDefault
package com.example.foo;
UPDATE: As of December 12th, 2012 JSR 305 is listed as "Dormant". According to the documentation:
A JSR that was voted as "dormant" by the Executive Committee, or one that has reached the end of its natural lifespan.
It looks like JSR 308 is making it into JDK 8 and although the JSR does not define @NotNull, the accompanying Checkers Framework
does. At the time of this writing, the Maven plugin is unusable due to this bug: https://github.com/typetools/checker-framework/issues/183
Eclipse has also its own annotations.
org.eclipse.jdt.annotation.NonNull
See at http://wiki.eclipse.org/JDT_Core/Null_Analysis for details.
Just pointing out that the Java Validation API (javax.validation.constraints.*
) doesn't come with a @Nullable
annotation, which is very valuable in a static analysis context. It makes sense for runtime bean validation as this is the default for any non-primitive field in Java (i.e. nothing to validate/enforce). For the purposes stated that should weigh towards the alternatives.
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
;-)
Android
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) {}
While waiting for this to be sorted out upstream (Java 8?), you could also just define your own project-local @NotNull
and @Nullable
annotations. This can be useful also in case you're working with Java SE, where javax.validation.constraints
isn't available by default.
import java.lang.annotation.*;
/**
* Designates that a field, return value, argument, or variable is
* guaranteed to be non-null.
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface NotNull {}
/**
* Designates that a field, return value, argument, or variable may be null.
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface Nullable {}
This would admittedly largely be for decorative or future-proofing purposes, since the above obviously doesn't in and of itself add any support for the static analysis of these annotations.
There are already too many answers here, but (a) it's 2019, and there's still no "standard" Nullable
and (b) no other answer references Kotlin.
The reference to Kotlin is important, because Kotlin is 100% interoperable with Java and it has a core Null Safety feature. When calling Java libraries, it can take advantage of those annotations to let Kotlin tools know if a Java API can accept or return null
.
As far as I know, the only Nullable
packages compatible with Kotlin are org.jetbrains.annotations
and android.support.annotation
(now androidx.annotation
). The latter is only compatible with Android so it can't be used in non-Android JVM/Java/Kotlin projects. However, the JetBrains package works everywhere.
So if you develop Java packages that should also work in Android and Kotlin (and be supported by Android Studio and IntelliJ), your best choice is probably the JetBrains package.
Maven:
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations-java5</artifactId>
<version>15.0</version>
</dependency>
Gradle:
implementation 'org.jetbrains:annotations-java5:15.0'
javax.annotation
, edu.umd.cs.findbugs.annotations
, org.eclipse.jdt.annotation
and lombok.NonNull
, as well as the implentation also including org.checkerframework
and io.reactivex.annotations
.
There is another way to do this in Java 8. I am doing 2 things to accomplish what I needed:
Making nullable fields explicit with types by wrapping nullable fields with java.util.Optional Checking that all non nullable fields are not null at construction time with java.util.Objects.requireNonNull
Example:
Edit: Disregard this 1st example, I'm just leaving here as context of the comments conversation. Skip to recommended option after this (2nd code block).
import static java.util.Objects.requireNonNull;
public class Role {
private final UUID guid;
private final String domain;
private final String name;
private final Optional<String> description;
public Role(UUID guid, String domain, String name, Optional<String> description) {
this.guid = requireNonNull(guid);
this.domain = requireNonNull(domain);
this.name = requireNonNull(name);
this.description = requireNonNull(description);
}
}
So my question is, do we even need to annotate when using java 8?
Edit: I found out later that some consider a bad practice to use Optional
in arguments, there is a good discussion with pros and cons here Why should Java 8's Optional not be used in arguments
Recommended option given that it is not best practice to use Optional in arguments, we need 2 constructors:
public class Role {
// Required fields, will not be null (unless using reflection)
private final UUID guid;
private final String domain;
private final String name;
// Optional field, not null but can be empty
private final Optional<String> description;
//Non null description
public Role(UUID guid, String domain, String name, String description) {
this.guid = requireNonNull(guid);
this.domain = requireNonNull(domain);
this.name = requireNonNull(name);
// description will never be null
requireNonNull(description);
// but wrapped with an Optional
this.description = Optional.of(description);
}
// Null description is assigned to Optional.empty
public Role(UUID guid, String domain, String name) {
this.guid = requireNonNull(guid);
this.domain = requireNonNull(domain);
this.name = requireNonNull(name);
this.description = Optional.empty();
}
//Note that this accessor is not a getter.
//I decided not to use the "get" suffix to distinguish from "normal" getters
public Optional<String> description(){ return description;}
}
new Role(null,null,null,null);
. With the annotations my IDE and static analysis will warn that null can't be passed into those parameters. Without it I don't find out until I run the code. That's the value of the annotations.
description
not null and client code could pass an empty String, but in many cases it could be handy to distinguish between and empty String and not having a value. Thanks for your comment. I will update the answer.
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:
Null pointer access: Error Violation of null specification: Error (linked to point #1) Potential null pointer access: Warning (otherwise facebook SDK would have warnings) Conflict between null annotations and null inference: Warning (linked to point #3)
@chaqke
.
If you are building your application using Spring Framework I would suggest using javax.validation.constraints.NotNull
comming from Beans Validation packaged in following dependency:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
The main advantage of this annotation is that Spring provides support for both method parameters and class fields annotated with javax.validation.constraints.NotNull
. All you need to do to enable support is:
supply the api jar for beans validation and jar with implementation of validator of jsr-303/jsr-349 annotations (which comes with Hibernate Validator 5.x dependency):
Example:
@Service
@Validated
public class MyServiceImpl implements MyService {
@Override
public Something doSomething(@NotNull String myParameter) {
// No need to do something like assert myParameter != null
}
}
When you try calling method doSomething and pass null as the parameter value, spring (by means of HibernateValidator) will throw ConstraintViolationException
. No need for manuall work here.
You can also validate return values.
Another important benefit of javax.validation.constraints.NotNull
comming for Beans Validation Framework is that at the moment it is still developed and new features are planned for new version 2.0.
What about @Nullable
? There is nothing like that in Beans Validation 1.1. Well, I could arguee that if you decide to use @NotNull
than everything which is NOT annotated with @NonNull
is effectively "nullable", so the @Nullable
annotation is useless.
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.
It is an internal thing. (no functional or technical impact)
With many many many usages.
IDE's like IntelliJ support custom @Nullable/@NotNull annotations.
Most frameworks prefer to use their own internal version as well.
Additional Questions (see comments):
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 ...
idea
tell nothing about void test(@NonNull String s) {}
called by test(null);
One of the nice things about IntelliJ is that you don't need to use their annotations. You can write your own, or you can use those of whatever other tool you like. You're not even limited to a single type. If you're using two libraries that use different @NotNull
annotations, you can tell IntelliJ to use both of them. To do this, go to "Configure Inspections", click on the "Constant Conditions & Exceptions" inspection, and hit the "Configure inspections" button. I use the Nullness Checker wherever I can, so I set up IntelliJ to use those annotations, but you can make it work with whatever other tool you want. (I have no opinion on the other tools because I've been using IntelliJ's inspections for years, and I love them.)
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!
Spring 5 has @NonNullApi at the package level. This seems like a convenient choice for a project that already has Spring dependencies. All fields, parameters and return values default to @NonNull and @Nullable can be applied in the few places that differ.
File package-info.java:
@org.springframework.lang.NonNullApi
package com.acme;
If you are using Spring 5.x / SpringBoot 2.x you should definitely use the Spring annotations (org.springframework.lang), as they provide you a default package-wide null check with the annotations @NonNullFields
and @NonNullApi
. You will not even have a clash with other NotNull/NonNull
annotations from other dependencies, as you are using @NonNullFields/@NonNullApi
. The annotations must be used in a file called package-info.java which is placed in the root directory of the package:
@NonNullFields
@NonNullApi
package org.company.test;
To exclude certain fields, parameters, or return values from the null check, just explicitly use the @Nullable
annotation. Instead of using @NonNullFields/@NonNullApi
you could also set @NonNull
everywhere, but probably it is better to activate null checks with @NonNullFields/@NonNullApi
by default and only do specific exceptions with @Nullable
.
The IDE (Intellij) will highlight code that violates the null conditions. If set up correctly, every developer can assume that fields, parameters and return values must be not null, unless there is a @Nullable
annotation. For more information check out this article.
Another option is the annotations provided with ANTLR 4. Following Pull Request #434, the artifact containing the @NotNull
and @Nullable
annotations includes an annotation processor that produces compile-time errors and/or warnings in the event one of these attributes is misused (for example, if both are applied to the same item, or if @Nullable
is applied to item with a primitive type). The annotation processor provides additional assurance during the software development process that the information conveyed by the application of these annotations is accurate, including in cases of method inheritance.
JSpecify is now the way to go. In fact: their presentation actively links to this very question and specifies that their goal is for it to finally have a good answer.
It has major participants like Android, Guava and Kotlin.
org.jspecify:jspecify:0.2.0
and that actually has 2 annotations. See github.com/jspecify/jspecify/releases Since it's still a beta, they stress to not use it in libraries yet.
newer projects should probably use jakarta.annotation-api (jakarta.annotation
package).
It is linked from now read-only javax.annotation repo and fits into the new jakarta ecosystem that aims to free community from all the javax
related headaches.
Success story sharing
javax.annotation
is that it's a) based on a dead JSR, b) hard to find an artifact that just provides the annotations and is maintained. The one from findbugs is not: search.maven.org/…javax.annotation
is that it causes problems with Java 9 because other modules also provide classes in that package (jax-ws).javax.annotation.NonNull
, never completed because its spec lead went AWOL. It had nothing to do with any decision by Oracle.