I have spent only a short time experimenting with @Nullable and @NotNull. This is
my best understanding so far. This information should not yet be relied on. I post
it now mainly hoping people who know much more than I do will offer correction.
Intellij introduced a design-by-contract annotation to verify that you are
handling nulls correctly. You can mark parameters, returns, or variables as either
@Nullable, meaning that can legitimately be
null, or @NotNull where
they may not be null.
Since that time, other groups have introduced similar but incompatible syntax. The
original IntelliJ scheme has the advantage that it does runtime as well as
compile-time checking. Further, the code for it is open source. IntelliJ Idea now
supports a some of the other schemes as well.
Important schemes include:
javax.validation.constraints.NotNull : available:
This would be your best choice if you are going to share your code.
- org.jetbrains.annotations.Nullable (formerly
com.intellij.annotations.NotNull)
- edu.umd.cs.findbugs.annotations.NonNull
The IntelliJ convention is you describe returns by putting the @Nullable/@NotNull before
everything in the method declaration, e.g. before the public. You describe parameters by putting the @Nullable/@NotNull before
everything in the parameter e.g. before the final.
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
...
@NotNull private String expand( @NotNull File targetFile,
@Nullable String image)
{
...
}
If your code violates the annotations, you will be warned to add specific code for
null checking, possibly an assert or if ( var !=
null ) perhaps overly conservatively. If you
don’t fix it, the code will still run, but could possibly throw a NullPointerException.
It is not as though you have to write more
code than you would normally (other than the annotations themselves). The annotations
just remind you about code you forgot to write.
If you am passing in a value to one method that requires @NotNull parameters and that value was obtained by another
method whose return value is marked @NotNull, you
need not write an explicit null check. That saves you
coding and reduces the need for overly conservative defensive programming.
Of course, you are not obligated to mark every return, parameter and variable with
an annotation. The unmarked ones you deal with at run time with a NullPointerException and/or with explicit null-checking code.
This sounds simple enough but there are quite a number of steps and complications
to getting it to work:
- The @Nullable and @NotNull annotations are an open source feature of the IntelliJ
IDE (Integrated Development Environment), not a feature of the Java language. Annotations
in general are, of course, built into Java. JetBrains have offered them to Oracle
to include in standard Java, but Oracle has not yet accepted them.
- The class files to implement org.jetbrains.annotations.Nullable
live in "X:\Program Files\JetBrains\IntelliJ IDEA 2017.3\lib\annotations.jar"
and "X:\Program Files\JetBrains\IntelliJ IDEA 2017.3\redist\annotations.jar".
- You have to configure the feature to work in IntelliJ. You must configure
"X:\Program Files\JetBrains\IntelliJ IDEA 2017.3\lib\annotations.jar" as one of the libraries accessible to your
module.
- In the project panel, click the name of your
project. This is the tricky part. You must click the project, not the
module to configure the module.
- Click Module Settings.
- Click Project.
- On the left, click modules.
- Click the name of one of your modules from the
middle column.
- Click Dependencies
- Click add.
- Click Single-entry module library
- Navigate to
"X:\Program Files\JetBrains\IntelliJ IDEA 2017.3\redist\annotations.jar".
- Click OK.
- Click OK.
- Strange as it sounds to the novice programmer, but it is also possible to store
your annotations separately from the source code, though the IntelliJ
IDE
will display them as if they were embedded. This ability in not peculiar to
IntelliJ. log4j, SLF4J, XStream, Spring, mysql-connector-j, commons-lang,
junit… all store information about the code separately from the source code,
many using the annotation mechanism. JSR-305 on Annotations for Software Defect
Detection is nothing but annotation.
- To make the annotations available to your JDK (Java Development Kit)
used by IntelliJ to compile your code (as distinct from the
JRE (Java Runtime Environment)
it uses to run the IDE), or to let ANT (A Neat Tool)
compile outside IntelliJ, you will need to install annotations.jar in your own various ext
directories. Theoretically you don’t need to put in all of them, but I find
it simpler to do so.
where to look for ext directories :
At this point all will work fine, except that if you reorganize your
imports the following lines will disappear:
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable
What you have to do now is configure the auto-import function to ignore these
imports:
- Click File.
- Click Settings.
- Click +Editor.
- Click Auto Import.
- Under Exclude from import and completion, click Add.
- Type org.jetbrains.annotations.NotNull
- Click Add again.
- Type org.jetbrains.annotations.Nullable
- Click OK.
- If you give your code to other people, their compiler won’t understand
the annotations. What do you do to allow others to deal with your annotations? In
general javac.exe just ignores annotations it does not
recognise. Thus others will need your "X:\Program Files\JetBrains\IntelliJ IDEA 2017.3\redist\annotations.jar". You would have to
bundle it with your source code distributions. They need to install annotations.jar in their JDK
ext directories e.g.
where to look for ext directories :
- Now insert some imports and annotations in your
source code and build.
Classpath Method
Mark Vedder said there is a much shorter way to accomplish
this, that works by adding the annotations.jar to the
classpath. I like to avoid using the classpath, since it so many cooks fiddle with
it.
- Type the @Nullable or @NotNull annotations in your source code.
- Hit alt+enter to invoke quick fix and select
Add 'annotations.jar' to classpath or
Add Maven dependency if it’s a Maven project.
- Click OK to the dialog and continue working.
- I suspect you still have to do some of the above steps in the long method.
Puzzles
- Does the IntelliJ IDE
evaluate the annotations or does Javac? or both?
- What is the best way to stop the imports from disappearing?
- What do you have to do so other people who do not own IntelliJ can build?
- Can people without IntelliJ use the annotations? If so, will they be evaluated
or ignored?