blob: 2205bf643f72cd4847ed0ac3eced408ecb19be25 [file] [log] [blame]
\chapterAndLabel{Frequently Asked Questions (FAQs)}{faq}
These are some common questions about the Checker Framework and about
pluggable type-checking in general. Feel free to suggest improvements to
the answers, or other questions to include here.
% Not supported by Hevea, so don't bother; instead do by hand:
% \minitoc
\newcommand{\faqtocpara}[1]{\paragraph{#1} ~}
%HEVEA \newcommand{\faqtocpara}[1]{\textbf{#1}}
\faqtocpara{\ref{faq-motivation-section}: Motivation for pluggable type-checking}
\\ \ref{faq-never-make-type-errors}: I don't make type errors, so would pluggable type-checking help me?
\\ \ref{faq-typequals-vs-subtypes}: Should I use pluggable types (type qualifiers), or should I used Java subtypes?
\faqtocpara{\ref{faq-getting-started-section}: Getting started}
\\ \ref{faq-annotate-existing-program}: How do I get started annotating an existing program?
\\ \ref{faq-first-checker}: Which checker should I start with?
\\ \ref{faq-checker-framework-dev}: How can I join the checker-framework-dev mailing list?
\faqtocpara{\ref{faq-usability-section}: Usability of pluggable type-checking}
\\ \ref{faq-ease-of-use}: Are type annotations easy to read and write?
\\ \ref{faq-code-clutter}: Will my code become cluttered with type annotations?
\\ \ref{faq-slowdown}: Will using the Checker Framework slow down my program? Will it slow down the compiler?
\\ \ref{faq-shorten-command-line}: How do I shorten the command line when invoking a checker?
\\ \ref{faq-pre-conditions}: Method pre-condition contracts, including formal parameter annotations, make no sense for public methods.
\faqtocpara{\ref{faq-warnings-section}: How to handle warnings}
\\ \ref{faq-handling-warnings}: What should I do if a checker issues a warning about my code?
\\ \ref{faq-interpreting-warnings}: What does a certain Checker Framework warning message mean?
\\ \ref{faq-warnings-square-brackets}: What do square brackets mean in a Checker Framework warning message?
\\ \ref{faq-no-absolute-guarantee}: Can a pluggable type-checker guarantee that my code is correct?
\\ \ref{faq-concurrency}: What guarantee does the Checker Framework give for concurrent code?
\\ \ref{faq-awarns}: How do I make compilation succeed even if a checker issues errors?
\\ \ref{faq-100-warnings}: Why does the checker always say there are 100 errors or warnings?
\\ \ref{faq-type-i-did-not-write}: Why does the Checker Framework report an error regarding a type I have not written in my program?
\\ \ref{faq-same-code-different-behavior}: Why does the Checker Framework accept code on one line but reject it on the next?
\\ \ref{faq-run-time-checking}: How can I do run-time monitoring of properties that were not statically checked?
\faqtocpara{\ref{faq-false-positives-section}: False positive warnings}
\\ \ref{faq-false-positive}: What is a ``false positive'' warning?
\\ \ref{faq-false-positive-extend-checker-framework}: How can I improve the Checker Framework to eliminate a false positive warning?
\\ \ref{faq-infer-fields}: Why doesn't the Checker Framework infer types for fields and method return types?
\\ \ref{faq-relationships-between-variables}: Why doesn't the Checker Framework track relationships between variables?
\\ \ref{faq-path-sensitive}: Why isn't the Checker Framework path-sensitive?
\faqtocpara{\ref{faq-syntax-section}: Syntax of type annotations}
\\ \ref{faq-receiver}: What is a ``receiver''?
\\ \ref{faq-annotation-after-type}: What is the meaning of an annotation after a type, such as \<@NonNull Object @Nullable>?
\\ \ref{faq-array-syntax-meaning}: What is the meaning of array annotations such as \<@NonNull Object @Nullable []>?
\\ \ref{faq-varargs-syntax-meaning}: What is the meaning of varargs annotations such as \<@English String @NonEmpty~...>?
\\ \ref{faq-type-qualifier-on-class-declaration}: What is the meaning of a type qualifier at a class declaration?
\\ \ref{faq-type-qualifier-on-bounds}: How are type qualifiers written on upper and lower bounds?
\\ \ref{faq-no-annotation-on-types-and-declarations}: Why shouldn't a qualifier apply to both types and declarations?
\\ \ref{faq-annotate-fully-qualified-name}: How do I annotate a
fully-qualified type name?
\\ \ref{faq-type-vs-declaration-annotations}: What is the difference between type annotations and declaration annotations?
\\ \ref{faq-declaration-annotations-moved}: How does the Checker Framework handle obsolete declaration annotations?
\faqtocpara{\ref{faq-semantics-section}: Semantics of type annotations}
\\ \ref{faq-typestate}: How can I handle typestate, or phases of my program with different data properties?
\\ \ref{faq-implicit-bounds}: Why are explicit and implicit bounds defaulted differently?
\\ \ref{faq-writing-generics}: How should I annotate code that uses generics?
\\ \ref{faq-runtime-retention}: Why are type annotations declared with \<@Retention(RetentionPolicy.RUNTIME)>?
\faqtocpara{\ref{faq-create-a-checker-section}: Creating a new checker}
\\ \ref{faq-create-a-checker}: How do I create a new checker?
\\ \ref{faq-type-properties}: What properties can and cannot be handled by type-checking?
\\ \ref{faq-declarative-syntax-for-type-rules}: Why is there no declarative syntax for writing type rules?
\faqtocpara{\ref{faq-tool-section}: Tool questions}
\\ \ref{faq-pluggable-type-checking}: How does pluggable type-checking work?
\\ \ref{faq-classpath-to-use-annotated-library}: What classpath is needed to use an annotated library?
\\ \ref{faq-classfile-annotations}: Why do \<.class> files contain more annotations than the source code?
\\ \ref{faq-checked-exceptions}: Is there a type-checker for managing checked and unchecked exceptions?
\\ \ref{faq-cf-is-slow}: The Checker Framework runs too slowly
\\ \ref{faq-version-number}: What does the Checker Framework version number mean?
\faqtocpara{\ref{faq-other-tools-section}: Relationship to other tools}
\\ \ref{faq-type-checking-vs-bug-detectors}: Why not just use a bug detector (like SpotBugs or Error Prone)?
\\ \ref{faq-eclipse}: How does the Checker Framework compare with Eclipse's Null Analysis?
\\ \ref{faq-nullaway}: How does the Checker Framework compare with NullAway?
\\ \ref{faq-optional}: How does the Checker Framework compare with the JDK's \<Optional> type?
\\ \ref{faq-jml}: How does pluggable type-checking compare with JML?
\\ \ref{faq-checker-framework-part-of-java}: Is the Checker Framework an official part of Java?
\\ \ref{faq-jsr-305}: What is the relationship between the Checker Framework and JSR 305?
\\ \ref{faq-jsr-308}: What is the relationship between the Checker Framework and JSR 308?
\sectionAndLabel{Motivation for pluggable type-checking}{faq-motivation-section}
\subsectionAndLabel{I don't make type errors, so would pluggable type-checking help me?}{faq-never-make-type-errors}
Occasionally, a developer says that he makes no errors that type-checking
could catch, or that any such errors are unimportant because they have low
impact and are easy to fix. When I investigate the claim, I invariably
find that the developer is mistaken.
Very frequently, the developer has underestimated what type-checking can
discover. Not every type error leads to an exception being thrown; and
even if an exception is thrown, it may not seem related to classical types.
Remember that a type system can discover
null pointer dereferences,
incorrect side effects,
security errors such as information leakage or SQL injection,
partially-initialized data,
wrong units of measurement,
and many other errors.
Every programmer makes errors sometimes and works with other people
who do.
Even where type-checking does not discover a
problem directly, it can indicate code with bad smells, thus revealing
problems, improving documentation, and making future maintenance easier.
There are other ways to discover errors, including extensive testing and
debugging. You should continue to use these.
But type-checking is a good complement to these. Type-checking is more
effective for some problems, and less effective for other problems. It can
reduce (but not eliminate) the time and effort that you spend on other
approaches. There are many important errors that type-checking and other
automated approaches cannot find; pluggable type-checking gives you more
time to focus on those.
\subsectionAndLabel{Should I use pluggable types (type qualifiers), or should I used Java subtypes?}{faq-typequals-vs-subtypes}
% Old labels, for backward compatibility. Don't use them any longer.
In brief, use subtypes when you can, and use type qualifiers when you cannot
use subtypes.
For some programming tasks, you can use either a Java subtype (interfaces
or subclasses) or a type
qualifier. As an example, suppose that your code currently uses \code{String} to
represent an address. You could use Java subclasses by creating a new
\code{Address} class and refactor your code to use it, or you could use
type qualifiers by creating an \code{@Address} annotation and applying it
to some uses of \code{String} in your code. As another example, suppose
that your code currently uses \code{MyClass} in two different ways that
should not interact with one another. You could use Java subclasses by
changing MyClass into an interface or abstract class, defining two
subclasses, and ensuring that neither subclass ever refers to the other
subclass nor to the parent class.
If Java subclasses solve your problem, then that is probably better.
We do not encourage you to use type qualifiers as a poor substitute for
classes. An advantage of using classes is that the Java type-checker
runs every time you compile your code;
by contrast, it is possible to forget to run the pluggable
type-checker. However, sometimes type qualifiers are a
better choice; here are some reasons:
\item[Backward compatibility]
Using a new class may make your code incompatible with existing libraries or
clients. Brian Goetz expands on this issue in an article on the
pseudo-typedef antipattern~\cite{Goetz2006:typedef}. Even if compatibility
is not a concern, a code change may introduce bugs, whereas adding
annotations does not change the run-time behavior. It is possible to add
annotations to existing code, including code you do not maintain or cannot
change. For code that strictly cannot be changed, you
can write library annotations (see Chapter~\ref{annotating-libraries}).
\item[Broader applicability]
Type annotations can be applied to primitives and to final classes such as
\code{String}, which cannot be subclassed.
\item[Richer semantics and new supertypes]
Type qualifiers permit you to remove operations, with a compile-time
guarantee. More
generally, type qualifiers permit creating a new supertype, not just a
subtype, of an existing Java type.
\item[More precise type-checking]
The Checker Framework is able to verify the correctness of code that the
Java type-checker would reject. Here are a few examples.
It uses a dataflow analysis to determine a more precise type for
variables after conditional tests or assignments.
It treats certain Java constructs more precisely, such as
reflection (see Chapter~\ref{reflection-resolution}).
It includes special-case logic for type-checking specific methods, such
as the Nullness Checker's treatment of \code{Map.get}.
Type qualifiers have no run-time representation. Therefore, there is no
space overhead for separate classes or for wrapper classes for
primitives. There is no run-time overhead for due to extra dereferences
or dynamic dispatch for methods that could otherwise be statically
\item[Less code clutter]
The programmer does not have to convert primitive types to wrappers,
which would make the code both uglier and slower. Thanks to defaults and
type refinement (Section~\ref{defaults}),
you may be able to write and think in terms of the
original Java type, rather than having to explicitly write one of the
subtypes in all locations.
For more details, see Section~\ref{faq-typequals-vs-subtypes}.
\sectionAndLabel{Getting started}{faq-getting-started-section}
\subsectionAndLabel{How do I get started annotating an existing program?}{faq-annotate-existing-program}
See Section~\ref{get-started-with-legacy-code}.
\subsectionAndLabel{Which checker should I start with?}{faq-first-checker}
You should start with a property that matters to you. Think about what
aspects of your code cause the most errors, or cost the most time during
maintenance, or are the most common to be incorrectly-documented. Focusing
on what you care about will give you the best benefits.
When you first start out with the Checker Framework, it's usually best to
get experience with an existing type-checker before you write your own new
Many users are tempted to start with the
\ahrefloc{nullness-checker}{Nullness Checker} (see
\chapterpageref{nullness-checker}), since null pointer errors are common
and familiar. The Nullness Checker works very well, but be warned of three
facts that make the absence of null pointer exceptions challenging to
Dereferences happen throughout your codebase, so there are a lot of
potential problems. By contrast, fewer lines of code are related to
locking, regular expressions, etc., so those properties are easier to
Programmers use \<null> for many different purposes. More seriously,
programmers write run-time tests against \<null>, and those are difficult
for any static analysis to capture.
The Nullness Checker interacts with initialization and map keys.
If null pointer exceptions are most important to you, then by all means use
the Nullness Checker. But if you just want to try \emph{some}
type-checker, there are others that are easier to use.
We do not recommend indiscriminately running all the checkers on your code.
The reason is that each one has a cost --- not just at compile time, but
also in terms of code clutter and human time to maintain the annotations.
If the property is important to you, is difficult for people to reason
about, or has caused problems in the past, then you should run that
checker. For other properties, the benefits may not repay the effort to
use it. You will be the best judge of this for your own code, of course.
%You might want to avoid some type-checkers when you are first starting out.
Some of the third-party checkers (see
have known bugs that limit their
usability. (Report the ones that affect you, so the developers
will prioritize fixing them.)
\subsectionAndLabel{How can I join the checker-framework-dev mailing list?}{faq-checker-framework-dev}
The \code{} mailing list is for
Checker Framework developers. Anyone is welcome to
\code{checker-framework-dev}}, after they have had several pull requests
Anyone is welcome to send mail to the
\code{} mailing list --- for
implementation details it is generally a better place for discussions than
the general \code{} mailing list,
which is for user-focused discussions.
Anyone is welcome to
\code{}} and send mail to it.
\sectionAndLabel{Usability of pluggable type-checking}{faq-usability-section}
\subsectionAndLabel{Are type annotations easy to read and write?}{faq-ease-of-use}
% This FAQ also appears in the JSR 308 FAQ.
% When I update one, also update the other.
The papers
pluggable types for Java''}~\cite{PapiACPE2008}
and using pluggable type-checkers''}~\cite{DietlDEMS2011}
discuss case studies in
which programmers
found type annotations to be natural to read and write. The code
continued to feel like Java, and the type-checking errors were easy to
comprehend and often led to real bugs.
You don't have to take our word for it, though. You can try the
Checker Framework for yourself.
The difficulty of adding and verifying annotations depends on your program.
If your program is well-designed and -documented, then skimming the
existing documentation and writing type annotations is extremely easy.
Otherwise, you may find yourself spending a lot of time trying to
understand, reverse-engineer, or fix bugs in your program, and then just a
moment writing a type annotation that describes what you discovered. This
process inevitably improves your code. You must decide whether it is a
good use of your time. For code that is not causing trouble now and is
unlikely to do so in the future (the code is bug-free, and you do not
anticipate changing it or using it in new contexts), then the
effort of writing type annotations for it may not be justified.
\subsectionAndLabel{Will my code become cluttered with type annotations?}{faq-code-clutter}
% This FAQ also appears in the JSR 308 FAQ.
% When I update one, also update the other.
In summary: annotations do not clutter code; they are used much
less frequently than generic types, which Java programmers find acceptable;
and they reduce the overall volume of documentation that a codebase needs.
As with any language feature, it is possible to write ugly code that
over-uses annotations. However, in normal use, very few annotations need
to be written. Figure 1 of the paper
pluggable types for Java}~\cite{PapiACPE2008} reports data for over
350,000 lines of type-annotated code:
1 annotation per 62 lines for nullness annotations (\<@NonNull>, \<@Nullable>, etc.)
% (/ (+ 4640 3961 10798) (+ 107 35 167))
1 annotation per 1736 lines for interning annotations (\<@Interned>)
% (/ 224048 129)
% ICSE 2011 paper says:
% Signature String Checker: less than 1 annotation per 500 lines of code
These numbers are for annotating existing code. New code that
is written with the type annotation system in mind is cleaner and more
correct, so it requires even fewer annotations.
Each annotation that a programmer writes replaces a sentence or phrase of
English descriptive text that would otherwise have been written in the
Javadoc. So, use of annotations actually reduces the overall size of the
documentation, at the same time as making it machine-processable
and less ambiguous.
\subsectionAndLabel{Will using the Checker Framework slow down my program? Will it slow down the compiler?}{faq-slowdown}
Using the Checker Framework has no impact on the execution of your program:
the compiler emits the identical bytecodes as the javac
compiler and so there is no run-time effect. Because there is no run-time
representation of type qualifiers, there is no way to use reflection to
query the qualifier on a given object, though you can use reflection to
examine a class/method/field declaration.
Using the Checker Framework does increase compilation time.
It can increase the compilation time by 2--10 times --- or more, if you run
many pluggable type-checkers at once. For workarounds, see
\subsectionAndLabel{How do I shorten the command line when invoking a checker?}{faq-shorten-command-line}
The compile options to javac can be long to type; for example,
\code{javac -processor org.checkerframework.checker.nullness.NullnessChecker ...}.
You can use shorthand for built-in checkers, such as \code{javac -processor
nullness ...} (see Section~\ref{shorthand-for-checkers}), or you can use
auto-discovery te eliminate the need for the \code{-processor} command-line
option (see Section~\ref{checker-auto-discovery}).
\subsectionAndLabel{Method pre-condition contracts, including formal parameter annotations, make no sense for public methods}{faq-pre-conditions}
Some people go further and say that pre-condition contracts make no sense
for any method. This objection is sometimes stated as, "A method parameter
should never be annotated as \<@NonNull>. A client could pass any value at
all, so the method implementation cannot depend on the value being
non-null. Furthermore, if a client passes an illegal value, it is the
method's responsibility to immediately tell the client about the illegal
Here is an example that invalidates this general argument. Consider a
binary search routine. Its specification requires that clients pass in a
sorted array.
/** Return index of the search key, if it is contained it the sorted array a; otherwise ... */
int binarySearch(Object @Sorted [] a, Object key)
The \<binarySearch> routine is fast --- it runs in O(log n) time where n is
the length of the array. If the routine had to validate that its input
array is sorted, then it would run in O(n) time, negating all benefit of
binary search. In other words, \<binarySearch> should \emph{not} validate
its input!
The nature of a contract is that if the \emph{caller} violates its
responsibilities by passing bad values, then the \emph{callee} is absolved
of its responsibilities. It is polite for the callee to try to provide a
useful diagnostic to the misbehaving caller (for example, by raising a
particular exception quickly), but it is \emph{not} required. In such a
situation, the callee has the flexibility to do anything that is
In some cases a routine has a \emph{complete} specification: the contract
permits the caller to pass any value, and the callee is required to throw
particular exceptions for particular inputs. This approach is common for
public methods, but it is not required and is not always the right thing.
As explained in section~\ref{annotate-normal-behavior}, even when a method
has a complete specification, the annotations should indicate normal
behavior: behavior that will avoid exceptions.
\sectionAndLabel{How to handle warnings and errors}{faq-warnings-section}
\subsectionAndLabel{What should I do if a checker issues a warning about my code?}{faq-handling-warnings}
For a discussion of this issue, see Section~\ref{handling-warnings}.
\subsectionAndLabel{What does a certain Checker Framework warning message mean?}{faq-interpreting-warnings}
Read the error message first; sometimes that is enough to clarify it.
Search through this manual for the text of the warning message or for words
that appear in it.
If nothing else explains it, then ask on the
list}. Be sure to say what you think it means or what specific part does
not make sense to you, and what you have already done to try to understand it.
\subsectionAndLabel{What do square brackets mean in a Checker Framework warning message?}{faq-warnings-square-brackets}
In a message like this:
found : ? extends T extends @UnknownKeyFor Object
required: [extends @UnknownKeyFor Object super @UnknownKeyFor null]
the square brackets enclose the upper and lower bounds that the type parameter needs to be within.
\subsectionAndLabel{Can a pluggable type-checker guarantee that my code is correct?}{faq-no-absolute-guarantee}
Each checker looks for certain errors. You can use multiple checkers to
detect more errors in your code, but you will never have a guarantee that
your code is completely bug-free.
If the type-checker issues no warning, then you have a guarantee that your
code is free of some particular error. There are some limitations to the
Most importantly, if you run a pluggable checker on only part of a program, then
you only get a guarantee that those parts of the program are error-free.
For example, if your code uses a library that has not been type-checked,
then the library might be incorrect, or your code might misuse the library.
As another example, suppose you have type-checked a framework that clients
are intended to extend. You should recommend that clients
run the pluggable checker. There is no way to force users to do so, so you
may want to retain dynamic checks or use other mechanisms to detect errors.
Section~\ref{checker-guarantees} states other limitations to a checker's
guarantee, such as regarding concurrency. Java's type system is also
unsound in certain situations, such as for arrays and casts (however, the
Checker Framework is sound for arrays and casts). Java uses dynamic checks
is some places it is unsound, so that errors are thrown at run time. The
pluggable type-checkers do not currently have built-in dynamic checkers to
check for the places they are unsound.
Writing dynamic checkers would be an interesting and valuable project.
Other types of dynamism in a Java application do not jeopardize the
guarantee, because the type-checker is conservative. For example, at a
method call, dynamic dispatch chooses some implementation of the method,
but it is impossible to know at compile time which one it will be. The
type-checker gives a guarantee no matter what implementation of the method
is invoked.
% This paragraph is weak.
Even if a pluggable checker cannot give an ironclad
guarantee of correctness, it is still useful. It can find errors,
exclude certain types of possible problems (e.g., restricting the
possible class of problems), improve documentation, and increase confidence
in your software.
\subsectionAndLabel{What guarantee does the Checker Framework give for concurrent code?}{faq-concurrency}
The Lock Checker (see Chapter~\ref{lock-checker}) offers a way to detect
and prevent certain concurrency errors.
By default, the Checker Framework assumes that the code that it is checking
is sequential: that is, there are no concurrent accesses from another
thread. This means that the Checker Framework is unsound for concurrent
code, in the sense that it may fail to issue a warning about errors that
occur only when the code is running in a concurrent setting.
For example, the Nullness Checker issues no warning for this
if (myobject.myfield != null) {
This code is safe when run on its own.
However, in the presence of multithreading, the call to \<toString> may
fail because another thread may set \<myobject.myfield> to \<null> after
the nullness check in the \<if> condition, but before the \<if> body is
If you supply the \<-AconcurrentSemantics> command-line option, then the
Checker Framework assumes that any field can be changed at any time. This
limits the amount of type refinement
(Section~\ref{type-refinement}) that the Checker Framework can do.
% If you are concerned about concurrency, then the ``fix''
% of putting data in a local variable doesn't fix the problem,
% just masks it from one particular checker. This is bad style and may make
% debugging harder rather than easier.
% For instance, suppose you have
% if (x.val != null) {
% x.val = x.val + 1;
% }
% which can suffer a null pointer exception if another thread nulls out
% x.val. The underlying problem is the possible concurrency error: the user
% should have used locks or some other mechanism to protect access to x.val.
% Changing this to
% myval = x.val;
% if (myval != null) {
% x.val = myval + 1;
% }
% does not fix the concurrency error, because no locking has been introduced.
% The code still has a data race that can lose updates or corrupt data
% structures. The code has been transformed so that the Nullness Checker
% does not issue a warning, but this is scant comfort since the code is no
% more correct than it was before.
% If you want to detect concurrency errors, then it is better to use a
% correct checker that is concurrency-aware, rather than an unsound one that
% encourages incorrect workarounds. Another way to put this is that a static
% checker should encourage better overall design, not just different bad
% designs.
\subsectionAndLabel{How do I make compilation succeed even if a checker issues errors?}{faq-awarns}
Section~\ref{running} describes the \<-Awarns> command-line
option that turns checker errors into warnings, so type-checking errors
will not cause \<javac> to exit with a failure status.
\subsectionAndLabel{Why does the checker always say there are 100 errors or warnings?}{faq-100-warnings}
By default, javac only reports the first 100 errors or warnings.
Furthermore, once javac encounters an error, it doesn't try compiling any
more files (but does complete compilation of all the ones that it has
started so far).
To see more than 100 errors or warnings, use the javac options \<-Xmaxerrs>
and \<-Xmaxwarns>. To convert Checker Framework errors into warnings so
that javac will process all your source files, use the option \<-Awarns>.
See Section~\ref{running} for more details.
\subsectionAndLabel{Why does the Checker Framework report an error regarding a type I have not written in my program?}{faq-type-i-did-not-write}
Sometimes, a Checker Framework warning message will mention a type you have
not written in your program. This is typically because a default has been
applied where you did not write a type; see Section~\ref{defaults}. In
other cases, this is because type refinement has given an
expression a more specific type than you wrote or than was defaulted; see
Note that an invocation of an impure method may cause the loss of all
information that was determined via type refinement; see
\subsectionAndLabel{Why does the Checker Framework accept code on one line but reject it on the next?}{faq-same-code-different-behavior}
Sometimes, the Checker Framework permits code on one line, but rejects the
same code a few lines later:
if (myField != null) {
myField.hashCode(); // no warning
myField.hashCode(); // warning about potential NullPointerException
The reason is explained in the section on type refinement
(Section~\ref{type-refinement}), which also tells how to specify the side
effects of \<someMethod> (Section~\ref{type-refinement-purity}).
\subsectionAndLabel{How can I do run-time monitoring of properties that were not statically checked?}{faq-run-time-checking}
Some properties are not checked statically (see
Chapter~\ref{suppressing-warnings} for reasons that code might not be
statically checked). In such cases, it would be desirable to check the
property dynamically, at run time.
Currently, the Checker Framework has no support for adding code to perform
run-time checking.
Adding such support would be an interesting and valuable project.
An example would be an option that causes the Checker Framework to
automatically insert a run-time check anywhere that static checking is
% such as casts
If you
are able to add run-time verification functionality, we would gladly
welcome it as a contribution to the Checker Framework.
Some checkers have library methods that you can explicitly insert in your
source code.
Examples include the Nullness Checker's
\refmethod{checker/nullness/util}{NullnessUtil}{castNonNull}{-T-} method (see
Section~\ref{suppressing-warnings-with-assertions}) and the Regex Checker's
\<RegexUtil> class (see Section~\ref{regexutil-methods}).
But, it would be better to have more general support that does not require
the user to explicitly insert method calls.
\sectionAndLabel{False positive warnings}{faq-false-positives-section}
\subsectionAndLabel{What is a ``false positive'' warning?}{faq-false-positive}
A ``false positive'' is when the tool reports a potential problem, but the
code is actually correct and will never violate the given property at run
The Checker Framework aims to be sound; that is, if the Checker Framework
does not report any possible errors, then your code is correct.
Every sound tool suffers false positive errors.
Wherever the Checker Framework issues an error, you can think of it as
saying, ``I can't prove this code is safe,'' but the code might be safe for
some complex, tricky reason that is beyond the capabilities of its
If you are sure that the warning is a false positive, you have several
Perhaps you just need to write annotations, especially on method signatures
but perhaps within method bodies as well.
Sometimes you can rewrite the code in a clearer way that the Checker
Framework can verify, and that might be easier for people to understand, too.
If these don't work, then you can suppress the warning
You also might want to report
the false positive in the Checker Framework issue tracker
(Section~\ref{reporting-bugs}), if it appears in real-world, well-written code.
Finally, you could improve the Checker Framework to make it more
precise, so that it does not suffer that false positive (see
\subsectionAndLabel{How can I improve the Checker Framework to eliminate a false positive warning?}{faq-false-positive-extend-checker-framework}
As noted in Section~\ref{faq-false-positive}, \emph{every} sound analysis
tool suffers false positives.
For any given false positive warning, it is theoretically possible to
improve the Checker Framework to eliminate it. (But, it's theoretically
impossible to eliminate all false positives. That is, there
will always exist some programs that don't go wrong at run time but for
which the Checker Framework issues a warning.)
Some improvements affect the implementation of the type system; they do not
add any new types. Such an improvement is invisible to users, except that
the users suffer fewer false positive warnings. This type of improvement
to the type checker's implementation is often worthwhile.
Other improvements change the type system or add a new type system.
Defining new types is a powerful way to improve precision, but it is costly
too. A simpler type system is easier for users to understand, less likely
to contain bugs, and more efficient.
By design, each type system in the Checker Framework has limited
expressiveness. Our goal is to implement enough functionality to handle
common, well-written real-world code, not to cover every possible
When reporting bugs, please focus on realistic scenarios. We are sure that
you can make up artificial code that stymies the type-checker! Those bugs
aren't a good use of your time to report nor the maintainers' time to
evaluate and fix. When reporting a bug, it's very helpful to minimize it
to give a tiny example that is easy to evaluate and fix, but please also
indicate how it arises in real-world, well-written code.
\subsectionAndLabel{Why doesn't the Checker Framework infer types for fields and method return types?}{faq-infer-fields}
Consider the following code. A programmer can tell that all three
invocations of \<format> are safe --- they never suffer an
\<IllegalFormatException> exception at run time:
class MyClass {
final String field = "%d";
String method() {
return "%d";
void method m() {
String local = "%d";
String.format(local, 5); // Format String Checker verifies the call is safe
String.format(field, 5); // Format String Checker warns the call might not be safe
String.format(method(), 5); // Format String Checker warns the call might not be safe
However, the Format String Checker can only verify the first call. It issues a
false positive warning about the second and third calls.
The Checker Framework can verify all three calls, with no false positive
warnings, if you annotate the type of \<field> and the return type of
\<method> as \<@Format(INT)>.
By default, the Checker Framework infers types for local variables
(Section~\ref{type-refinement}), but not for fields and method return
types. (The Checker Framework includes a whole-program type inference tool
that infers field and method return types; see
There are several reasons for this design choice.
\item[Separation of specification from implementation]
The designer of an API makes certain promises to clients; these are
codified in the API's specification or contract. The implementation
might return a more specific type today, but the designer does not want
clients to depend on that. For example, a string might happen to be a
regular expression because it contains no characters with special meaning
in regexes, but that is not guaranteed to always be true. It's better
for the programmer to explicitly write the intended specification.
\item[Separate compilation]
To infer types for a non-final method, it is necessary to examine every
overriding implementation, so that the method's return type annotation is
compatible with all values that are returned by any overriding
implementation. In general, examining all implementations is impossible,
because clients may override the method. When possible, it is
inconvenient to provide all that source code, and it would slow down the
A related issue is that determining which values can be returned by a
method $m$ requires analyzing $m$'s body, which requires analyzing
all the methods called by $m$, and so forth. This quickly devolves to
analyzing the whole program.
Determining all possible values assigned to a field is equally hard.
Type-checking is modular --- it works on one procedure at a time,
examining that procedure and the specifications (not implementations) of
methods that it calls. Therefore, type-checking is fast and can work on
partial programs. The Checker Framework performs modular type-checking,
not a whole-program analysis.
\item[Order of compilation]
When the compiler is called on class \<Client> and class \<Library>, the
programmer has no control over which class is analyzed first. When the
first class is compiled, it has access only to the signature of the other
class. Therefore, a programmer would see inconsistent results depending
on whether \<Client> was compiled first and had access only to the
declared types of \<Library>, or the \<Library> was compiled first and
the compiler refined the types of its methods and fields before \<Client>
looked them up.
\item[Consistent behavior with or without pluggable type-checking]
The \<.class> files produced with or without pluggable type-checking
should specify the same types for all public fields and methods. If
pluggable type-checking changed the those types, then users would be
confused. Depending on how a library was compiled, pluggable
type-checking of a client program would give different results.
% In the future, the Checker Framework may infer types for final fields; if
% programmers see inconsistent results, they should write types explicitly.
\subsectionAndLabel{Why doesn't the Checker Framework track relationships between variables?}{faq-relationships-between-variables}
The Checker Framework estimates the possible run-time value of each
variable, as expressed in a type system. In general, the Checker Framework
does estimate relationships between two variables, except for specific
relationships listed in Section~\ref{java-expressions-as-arguments}.
For example, the Checker Framework does not track which variables are equal
to one another. The Nullness Checker issues a warning, ``dereference of
possibly-null reference y'', for expression \<y.toString()>:
void nullnessExample1(@Nullable Object x) {
Object y = x;
if (x != null) {
Code that checks one variable and then uses a different variable is
confusing and is often considered poor style.
The Nullness Checker is able to verify the correctness of a small variant
of the program, thanks to type refinement
void nullnessExample12(@Nullable Object x) {
if (x != null) {
Object y = x;
The difference is that in the first example, nothing was known about \<x> at
the time \<y> was set to it, and so the Nullness Checker recorded no facts
about \<y>. In the second example, the Nullness Checker knew that \<x>
was non-null when \<y> was assigned to it.
In the future, the Checker Framework could be enriched by tracking which
variables are equal to one another, a technique called ``copy
This would handle the above examples, but wouldn't handle other examples.
For example, the following code is safe:
void requiresPositive(@Positive int arg) {}
void intExample1(int x) {
int y = x*x;
if (x > 0) {
void intExample2(int x) {
int y = x*x;
if (y > 0) {
However, the Index Checker (\chapterpageref{index-checker}), which defines the
\refqualclass{checker/index/qual}{Positive} type qualifier, issues warnings
saying that it cannot prove that the arguments are \<@Positive>.
A slight variant of \<intExample1> can be verified:
void intExample1a(int x) {
if (x > 0) {
int y = x*x;
No variant of \<intExample2> can be verified. It is not worthwhile to make
the Checker Framework more complex and slow by tracking rich properties
such as arbitrary arithmetic.
As another example of a false positive warning due to arbitrary arithmetic
properties, consider the following code:
void falsePositive2(int arg) {
Object o;
if (arg * arg >= arg) { // always true!
o = new Object();
o.toString(); // Nullness Checker issues a false positive warning
\subsectionAndLabel{Why isn't the Checker Framework path-sensitive?}{faq-path-sensitive}
The Checker Framework is not path-sensitive. That is, it maintains one
estimate for each variable, and it assumes at every branch (such as \<if>
statement) that every choice could be taken.
In the following code, there are two \<if> statements.
void falsePositive1(boolean b) {
Object o;
if (b) {
o = new Object();
if (b) {
o.toString(); // Nullness Checker issues a false positive warning
In general, if code has two \<if> statements in succession, then there are
4 possible paths through the code: [true, true], [true, false], [false,
true], and [false, false]. However, for this code only two of those
paths are feasible: namely, [true, true] and [false, false].
The Checker Framework is not path-sensitive, so it issues a warning.
The lack of path-sensitivity can be viewed as special case of the fact that
the Checker Framework maintains a single estimate for each variable value,
rather than tracking relationships between multiple variables
Making the Checker Framework path-sensitive would make it more powerful,
but also much more complex and much slower. We have not yet found this
\sectionAndLabel{Syntax of type annotations}{faq-syntax-section}
There is also a separate FAQ for the type annotations syntax
\subsectionAndLabel{What is a ``receiver''?}{faq-receiver}
The \emph{receiver} of a method is the \<this> formal parameter, sometimes
also called the ``current object''. Within the method declaration, \<this>
is used to refer to the receiver formal parameter. At a method call, the
receiver actual argument is written before a period and the method name.
The method \<compareTo> takes \emph{two} formal parameters. At a call site
like \<x.compareTo(y)>, the two arguments are \<x> and \<y>. It is
desirable to be able to annotate the types of both of the formal
parameters, and doing so is supported by both Java's type annotations
syntax and by the Checker Framework.
A type annotation on the receiver is treated exactly like a type annotation
on any other formal parameter. At each call site, the type of the argument
must be a consistent with (a subtype of or equal to) the declaration of the
corresponding formal parameter. If not, the type-checker issues a warning.
Here is an example. Suppose that \<@A Object> is a supertype of \<@B
Object> in the following declaration:
class MyClass {
void requiresA(@A MyClass this) { ... }
void requiresB(@B MyClass this) { ... }
Then the behavior of four different invocations is as follows:
@A MyClass myA = ...;
@B MyClass myB = ...;
myA.requiresA() // OK
myA.requiresB() // compile-time error
myB.requiresA() // OK
myB.requiresB() // OK
The invocation \<myA.requiresB()> does not type-check because the actual
argument's type is not a subtype of the formal parameter's type.
A top-level constructor does not have a receiver. An inner class
constructor does have a receiver, whose type is the same as the containing
outer class. The receiver is distinct from the object being constructed.
In a method of a top-level class, the receiver is named \<this>. In a
constructor of an inner class, the receiver is named \<Outer.this> and the
result is named \<this>.
A method in an anonymous class has a receiver, but it is not possible to
write the receiver in the formal parameter list because there is no name
for the type of \<this>.
\subsectionAndLabel{What is the meaning of an annotation after a type, such as \<@NonNull Object @Nullable>?}{faq-annotation-after-type}
In a type such as \<@NonNull Object @Nullable []>, it may appear that the
\<@Nullable> annotation is written \emph{after} the type \<Object>. In
fact, \<@Nullable> modifies \<[]>. See the next FAQ, about array
annotations (Section~\ref{faq-array-syntax-meaning}).
\subsectionAndLabel{What is the meaning of array annotations such as \<@NonNull Object @Nullable []>?}{faq-array-syntax-meaning}
You should parse this as:
(\textbf{\<@NonNull Object>}) (\textbf{\<@Nullable []>}).
Each annotation precedes the component of the type that it qualifies.
\<@NonNull Object @Nullable []> is a possibly-null array of non-null
objects. Note that the first token in the type,
``\<@NonNull>'', applies to the element
type \<Object>, not to the array type as a whole. The annotation \<@Nullable> applies to the
array (\<[]>).
\<@Nullable Object @NonNull []> is a non-null array of possibly-null
Some older tools have inconsistent semantics for annotations on array and
varargs elements. Their semantics is unfortunate and confusing; developers
should convert their code to use type annotations instead.
Section~\ref{declaration-annotations-moved} explains how the Checker
Framework handles declaration annotations in the meanwhile.
\subsectionAndLabel{What is the meaning of varargs annotations such as \<@English String @NonEmpty~...>?}{faq-varargs-syntax-meaning}
Varargs annotations are treated similarly to array annotations.
(A way to remember this is that
when you write a varargs formal parameter such as
\<void method(String... x) \ttlcb\ttrcb>, the Java compiler generates a
method that takes an array of strings; whenever your source code calls the
method with multiple arguments, the Java compiler packages them up into an
array before calling the method.)
Either of these annotations
void method(String @NonEmpty [] x) {}
void method(String @NonEmpty ... x) {}
applies to the array: the method takes a non-empty array of strings, or
the varargs list must not be empty.
Either of these annotations
void method(@English String [] x) {}
void method(@English String ... x) {}
applies to the element type. The annotation documents that the method takes an array of English strings.
\subsectionAndLabel{What is the meaning of a type qualifier at a class declaration?}{faq-type-qualifier-on-class-declaration}
See Section~\ref{upper-bound-for-use}.
\subsectionAndLabel{How are type qualifiers written on upper and lower bounds?}{faq-type-qualifier-on-bounds}
See Section~\ref{generics-instantiation}.
\subsectionAndLabel{Why shouldn't a qualifier apply to both types and declarations?}{faq-no-annotation-on-types-and-declarations}
It is bad style for an annotation to apply to both types and declarations.
In other words, every annotation should have a \<@Target> meta-annotation,
and the \<@Target> meta-annotation should list either only declaration
locations or only type annotations. (It's OK for an annotation to target
both \<ElementType.TYPE\_PARAMETER> and \<ElementType.TYPE\_USE>, but no
other declaration location along with \<ElementType.TYPE\_USE>.)
Sometimes, it may seem tempting for an annotation to apply to both type
uses and (say) method declarations. Here is a hypothetical example:
``Each \<Widget> type may have a \<@Version> annotation.
I wish to prove that versions of widgets don't get assigned to
incompatible variables, and that older code does not call newer code (to
avoid problems when backporting).
A \<@Version> annotation could be written like so:
@Version("2.0") Widget createWidget(String value) { ... }
\<@Version("2.0")> on the method could mean that the \<createWidget> method
only appears in the 2.0 version. \<@Version("2.0")> on the return type
could mean that the returned \<Widget> should only be used by code that
uses the 2.0 API of \<Widget>. It should be possible to specify these
independently, such as a 2.0 method that returns a value that allows the
1.0 API method invocations.''
Both of these are type properties and should be specified with type
annotations. No method annotation is necessary or desirable. The best way
to require that the receiver has a certain property is to use a type
annotation on the receiver of the method. (Slightly more formally, the
property being checked is compatibility between the annotation on the type
of the formal parameter receiver and the annotation on the type of the
actual receiver.) If you do not know what ``receiver'' means, see
Another example of a type-and-declaration annotation that represents poor
design is JCIP's \<@GuardedBy> annotation~\cite{Goetz2006}. As discussed
in Section~\ref{lock-jcip-annotations}, it means two different things when
applied to a field or a method. To reduce confusion and increase
expressiveness, the Lock Checker (see Chapter~\ref{lock-checker}) uses the
\<@Holding> annotation for one of these meanings, rather than overloading
\<@GuardedBy> with two distinct meanings.
A final example of a type-and-declaration annotation is some \<@Nullable>
or \<@NonNull> annotations that are intended to work both with modern tools
that process type annotations and with old tools that were written before
Java had type annotations. Such type-and-declaration annotations were a
temporary measure, intended to be used until the tool supported Java 8
(which was released in March 2014), and
should not be necessary any longer.
\subsectionAndLabel{How do I annotate a fully-qualified type name?}{faq-annotate-fully-qualified-name}
If you write a fully-qualified type name in your program, then the Java
language requires you to write a type annotation on the simple name part,
such as
entity.hibernate. @Nullable User x;
If you try to write the type annotation before the entire fully-qualified
name, such as
@Nullable entity.hibernate.User x; // illegal Java syntax
then you will get an error like one of the following:
error: scoping construct for static nested type cannot be annotated
error: scoping construct cannot be annotated with type-use annotation
\subsectionAndLabel{What is the difference between type annotations and declaration annotations?}{faq-type-vs-declaration-annotations}
Java has two distinct varieties of annotation: type annotations and
declaration annotations.
A \textbf{type annotation} can be written on any use of a \textbf{type}.
It conceptually creates a new, more specific type.
That is, it describes what values the type represents.
As an example, the \<int> type contains these values: ..., -2, -1, 0, 1, 2, ... \\
The \<@Positive int> type contains these values: 1, 2, ... \\
Therefore, \<@Positive int> is a subtype of \<int>.
A \textbf{declaration annotation} can be written on any \textbf{declaration} (a class, method, or variable). It describes the thing being declared, but does not describe run-time values. Here are examples of declaration annotations:
@Deprecated // programmers should not use this class
class MyClass { ... }
@Override // this method overrides a method in a supertype
void myMethod() { ... }
@SuppressWarnings(...) // compiler should not warn about the initialization expr
Here are examples that use both a declaration annotation and a type annotation:
@Regex String getPattern() { ... }
@NonNull String myField;
Note that the type annotation describes the value, and the declaration annotation says something about the method or use of the field.
As a matter of style, declaration annotations are written on their own line, and type annotations are written directly before the type, on the same line.
\label{declaration-annotations-moved} % temporary, for backward compatibility
\subsectionAndLabel{How does the Checker Framework handle obsolete declaration annotations?}{faq-declaration-annotations-moved}
When a declaration annotation is an alias for a type annotation, the
Checker Framework may move the annotation before replacing it by the
canonical version. (If the declaration annotation is in an \<org.checkerframework>
package, it is not moved.)
For example,
@NonNull Object [] returnsArray();
is treated as if the programmer had written
import org.checkerframework.checker.nullness.qual.NonNull;
Object @NonNull [] returnsArray();
because Android's \<@NonNull> annotation is a declaration annotation, which
is understood to apply to the top-level return type of the annotated method.
When possible, you should use type annotations rather than declaration
Users who are using old Java 5--7 declaration annotations (for instance,
from the FindBugs tool, which has not been maintained since 2015, and from
its successor SpotBugs, which has not yet adopted type annotations, even
though type annotations were added to Java in 2014) can use annotations in
package \<org.checkerframework.checker.nullness.compatqual> to avoid name
conflicts. These are available in package
on Maven Central. Once the users are ready to upgrade to Java 8+ type
annotations, those compatibility annotations are no longer necessary.
\sectionAndLabel{Semantics of type annotations}{faq-semantics-section}
\subsectionAndLabel{How can I handle typestate, or phases of my program with different data properties?}{faq-typestate}
Sometimes, your program works in phases that have different behavior. For
example, you might have a field that starts out null and becomes non-null
at some point during execution, such as after a method is called. You can
express this property as follows:
Annotate the field type as \refqualclass{checker/nullness/qual}{MonotonicNonNull}.
Annotate the method that sets the field as \refqualclass{checker/nullness/qual}{EnsuresNonNull}\<(">\emph{\<myFieldName>}\<")>.
(If method \<m1> calls method \<m2>, which actually sets the field, then
you would probably write this annotation on both \<m1> and \<m2>.)
Annotate any method that depends on the field being non-null as
The type-checker will verify that such a method is only called when the
field isn't null --- that is, the method is only called after the setting
You can also use a typestate checker (see
\chapterpageref{typestate-checker}), but they have not been as extensively
\subsectionAndLabel{Why are explicit and implicit bounds defaulted differently?}{faq-implicit-bounds}
The following two bits of code have the same semantics under Java, but are
treated differently by the Checker Framework's CLIMB-to-top defaulting
rules (Section~\ref{climb-to-top}):
class MyClass<T> { ... }
class MyClass<T extends Object> { ... }
The difference is the annotation on the upper bound of the type argument
\<T>. They are treated in the following way.
class MyClass<T> == class MyClass<T extends @TOPTYPEANNO Object>
class MyClass<T extends Object> == class MyClass<T extends @DEFAULTANNO Object>
\<@TOPTYPEANNO> is the top annotation in the type qualifier hierarchy. For
example, for the nullness type system, the top type annotation is
\<@Nullable>, as shown in Figure~\ref{fig-nullness-hierarchy}.
\<@DEFAULTANNO> is the default annotation for the type system. For
example, for the nullness type system, the default type annotation is
In some type systems, the top qualifier and the default are the same. For
such type systems, the two code snippets shown above are treated the same.
An example is the regular expression type system; see
The CLIMB-to-top rule reduces the code edits required to annotate an
existing program, and it treats types written in the program consistently.
When a user writes no upper bound, as in
\code{class C<T> \ttlcb\ ... \ttrcb},
then Java permits the class to be instantiated with any type parameter.
The Checker Framework behaves exactly the same, no matter what the default
is for a particular type system --- and no matter whether the user has
changed the default locally.
When a user writes an upper bound, as in
\code{class C<T extends OtherClass> \ttlcb\ ... \ttrcb},
then the Checker Framework treats this occurrence of \<OtherClass> exactly
like any other occurrence, and applies the usual defaulting rules. Use of
\<Object> is treated consistently with all other types in this location and
all other occurrences of \<Object> in the program.
Here are some style guidelines:
Omit the \<extends> clause when possible. To indicate no constraints on
type qualifiers, write \code{class MyClass<T>} rather than \code{class
MyClass<T extends @TOPTYPEANNO Object>}.
When you write an \<Object> upper bound, give an explicit type annotation.
That is, write \code{class C<T extends @DEFAULTANNO Object>
\ttlcb\ ... \ttrcb} even though it is equivalent to writing
\code{class C<T extends Object> \ttlcb\ ... \ttrcb}.
If you write just \<extends Object>, then someone who is reading the code
might think that it is irrelevant (which it is in plain Java). Also,
some IDEs will suggest removing it.
\subsectionAndLabel{How should I annotate code that uses generics?}{faq-writing-generics}
Suppose unannotated code contains a type parameter \code{<T>}. How should
you annotate that?
This is really a question about Java's generic types, so if you understand
Java generics, this question is moot. However, Java generics can be hard
to understand, so here is a brief explanation of some concrete annotations,
using nullness annotations for concreteness.
Any type argument may be supplied for \code{T}.
It is equivalent to \code{<T extends @Nullable Object>}, because
\code{@Nullable Object} is the top type in the type hierarchy.
\item[\code{<T extends @Nullable Object>}]
Any type argument may be supplied for \code{T}.
It is equivalent to \code{<T>}, as noted above.
\item[\code{<T extends Object>}]
\code{T} can be instantiated by any type whose qualifier is \code{@NonNull}.
The default annotation is \code{@NonNull}, and annotation defaults apply
to type uses such as \code{Object} but not to type variables such as
\code{T}. Therefore, \code{<T extends Object>} is equivalent to
\code{<T extends @NonNull Object>}. It permits any type argument that is
a subtype of \code{@NonNull Object}, which is any type argument whose
qualifier is \code{@NonNull} since \code{@NonNull} is the bottom type
qualifier in the type qualifier hierarchy.
\item[\code{<T extends @NonNull Object>}]
\code{T} can be instantiated by any type whose qualifier is \code{@NonNull}.
It is equivalent to \code{<T extends Object>}, as noted above.
\item[\code{<@Nullable T>}]
\code{T} can be instantiated by any type whose qualifier is \code{@Nullable}.
The annotation \code{@Nullable} before \code{T} applies to \code{T}'s
implicit lower bound. There is no explicit upper bound (that is, no
\code{extends}), so the upper bound is the top type, \code{@Nullable
Object}, just as for \code{<T>}, which was discussed above. Therefore,
\code{<@Nullable T>} is the same as \code{<T super @Nullable void extends
@Nullable Object>}, except that the latter is not legal Java.
\item[\code{<T super @Nullable String>}]
\code{T} can be instantiated by any supertype of \code{@Nullable String},
which is any supertype of \code{String} (\code{Object},
\code{Serializable}, \code{CharSequence}, etc.) so long as its type
qualifier is \code{@Nullable}.
\item[\code{<T super @NonNull String>}]
\code{T} can be instantiated by any supertype of \code{@NonNull String}.
Since \<@NonNull> is the bottom type qualifier, the instantiating type
can have any type qualifier.
For more details about how the Checker Framework supports generics and
polymorphism, see \chapterpageref{polymorphism}
\subsectionAndLabel{Why are type annotations declared with \<@Retention(RetentionPolicy.RUNTIME)>?}{faq-runtime-retention}
Annotations such as \refqualclass{checker/nullness/qual}{NonNull} are
declared with
\<\sunjavadocanno{java.base/java/lang/annotation/Retention.html}{Retention}(RetentionPolicy.\sunjavadoc{java.base/java/lang/annotation/RetentionPolicy.html\#RUNTIME}{RUNTIME})>. In other words,
these type annotations are available to tools at run time. Such run-time
tools could check the annotations (like an \<assert> statement), type-check
dynamically-loaded code, check casts and \<instanceof> operations, resolve
reflection more precisely, or other tasks that we have not yet thought of.
Not many such tools exist today, but the annotation designers wanted to
accommodate them in the future.
\<RUNTIME> retention has negligible costs (no run-time dependency, minimal
increase in heap size).
For the purpose of static checking at compile time,
retention would be sufficient. Note that
retention would not be sufficient, because of separate compilation: when
type-checking a class, the compiler needs to read the annotations on
libraries that it uses, and separately-compiled libraries are available to
the compiler only as class files.
\sectionAndLabel{Creating a new checker}{faq-create-a-checker-section}
\subsectionAndLabel{How do I create a new checker?}{faq-create-a-checker}
In addition to using the checkers that are distributed with the Checker
Framework, you can write your own checker to check specific properties that
you care about. Thus, you can find and prevent the bugs that are most
important to you.
Chapter~\ref{creating-a-checker} gives
complete details regarding how to write a checker. It also suggests places
to look for more help, such as the \href{../api/}{Checker Framework
API documentation (Javadoc)} and the source code of the distributed
To whet your interest and demonstrate how easy it is to get started, here
is an example of a complete, useful type-checker.
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
public @interface Encrypted {}
Section~\ref{subtyping-example} explains this checker and tells
you how to run it.
\subsectionAndLabel{What properties can and cannot be handled by type-checking?}{faq-type-properties}
In theory, any property about a program can be expressed and checked within
a type system. In practice, types are a good choice for some properties
and a bad choice for others.
A type expresses the set of possible values for an expression. Therefore,
types are a good choice for any property that is about variable values or
Types are a poor choice for expressing properties about timing, such as
that action B will happen within 10 milliseconds of action A. Types are
not good for verifying the results of calculations; for example, they could
ensure that code always call an \<encrypt> routine in the appropriate
places, but not that the \<encrypt> routine is correctly implemented.
Types are not a good solution for preventing infinite loops, except perhaps
in special cases.
\subsectionAndLabel{Why is there no declarative syntax for writing type rules?}{faq-declarative-syntax-for-type-rules}
A type system implementer can declaratively specify the type qualifier
hierarchy (Section~\ref{creating-declarative-hierarchy}) and the type introduction rules
(Section~\ref{creating-type-introduction}). However, the Checker
Framework uses a procedural syntax for specifying type-checking
rules (Section~\ref{creating-extending-visitor}).
A declarative syntax might be more concise, more readable, and more
verifiable than a procedural syntax.
We have not found the procedural syntax to be the most important impediment
to writing a checker.
Previous attempts to devise a declarative syntax
for realistic type systems have failed; see a technical
paper~\cite{PapiACPE2008} for a discussion. When an
adequate syntax exists, then the Checker Framework can be extended to
support it.
\sectionAndLabel{Tool questions}{faq-tool-section}
\subsectionAndLabel{How does pluggable type-checking work?}{faq-pluggable-type-checking}
The Checker Framework enables you to define a new type system. It finds
errors, or guarantees their absence, by performing type-checking that is
similar to that already performed by the Java compiler.
Type-checking examines each statement of your program in turn, one at a time.
Expressions are processed bottom-up. Given types for each sub-expression,
the type-checker determines whether the types are legal for the
expression's operator and determines the type of the expression.
% For example, if \<x> has type \<@Positive> and \<y> has type \<@Positive>,
% then the expression \<x + y> also has type @Positive.
An assignment is legal if the type of the right-hand side is a subtype of
the declared type of the left-hand side.
At a method call, the arguments are legal if they can be assigned to the
formal parameters (this is called a ``pseudo-assignment'' and it follows
the normal rules for assignment). The type of the method call is the
declared type of the return type, where the method is declared. If
the method declaration is not annotated, then a default annotation is
Suppose that method \<Sub.m> overrides method \<Super.m>.
The return type of \<Sub.m> must be equal to or a subtype of the return
type of \<Super.m> (this is called ``covariance'').
The type of formal parameter $i$ of \<Sub.m> must be equal to or a
\emph{super}type of the type of formal parameter $i$ in \<Super.m> (this
is called ``contravariance'').
\subsectionAndLabel{What classpath is needed to use an annotated library?}{faq-classpath-to-use-annotated-library}
Suppose that you distribute a library, which contains Checker Framework
annotations such as \<@Nullable>. This enables clients of the library to
use the Checker Framework to type-check their programs. To do so, they
must have the Checker Framework annotations on their classpath, for
instance by using the Checker Framework Compiler.
Clients who do not wish to perform pluggable type-checking do not need to
have the Checker Framework annotations
(\<checker-qual.jar>) in their classpath, either when compiling or running
their programs.
The JVM does not issue a link error if an annotation is not found when a
class is loaded. (By contrast, the JVM does issue a link error if a
superclass, or a parameter/return/field type, is not found.)
Likewise, there is no problem compiling against a library even if the
library's annotations are not on the classpath.
These are properties of Java, and are not specific to the Checker
Framework's annotations.
\subsectionAndLabel{Why do \<.class> files contain more annotations than the source code?}{faq-classfile-annotations}
A \<.class> file contains an annotation on every type, as computed by
defaulting rules; see Section~\ref{effective-qualifier}.
When an overridden method has a side effect annotation, the overriding
method must have one too. However, if the side effect annotation is
declared with the \refqualclass{framework/qual}{InheritedAnnotation}
meta-annotation, the Checker Framework automatically adds the missing
annotation. This is the case for most side effect annotations --- these
annotations are propagated from annotated libraries, such as the JDK, to
your code.
\subsectionAndLabel{Is there a type-checker for managing checked and unchecked exceptions?}{faq-checked-exceptions}
It is possible to annotate exception types, and any type-checker built on the
Checker Framework enforces that type annotations are consistent between
\<throw> statements and \<catch> clauses that might catch them.
The Java compiler already enforces that all checked exceptions are caught
or are declared to be passed through, so you would use annotations to
express other properties about exceptions.
Checked exceptions are an example of a ``type and effect'' system, which is
like a type system but also accounts for actions/behaviors such as side
effects. The GUI Effect Checker (\chapterpageref{guieffect-checker}) is a
type-and-effect system that is distributed with the Checker Framework.
\subsectionAndLabel{The Checker Framework runs too slowly}{faq-cf-is-slow}
Using a pluggable type-checker increases compile times by a factor of 2--10.
Slow compilation speed is probably the worst thing about the Checker
To improve performance:
Ensure that the Checker Framework has enough memory. The Checker
Framework uses more memory than \<javac> does, and Java's default heap
limit is so small that the Checker Framework might spend most of its time
in garbage collection. (If this is the case, the Checker Framework will
issue a warning ``Garbage collection consumed over 25\% of CPU during the
past minute.") For example, you might pass an argument like
\<-Xmx3g>, or set an environment variable like \<export
\_JAVA\_OPTIONS=-Xmx3g>, to permit the Checker Framework to use up to 3GB
of memory. If you use Java 8, consider upgrading to Java 11, which has
better memory management.
Set your build system to perform \emph{incremental compilation}. When
compiling just a few source files (the size of a typical edit or commit),
you won't notice the slowdown even if the Checker Framework is very slow.
If you compile all files in a large project, you will definitely notice a
slowdown. You should structure your build system to make compiling all
files rare, by declaring dependencies and using caching.
(Note: Maven lacks dependency-driven build and caching. If your project
uses Maven, consider switching to a more capable build system such as Gradle.)
% (Note that some build systems have a bug, in that they unnecessarily always
% re-run compilation that uses annotation processors.)
If the Checker Framework is still too slow for you to run on every compilation,
you can run it periodically, such as in a Git commit hook or in continuous
The Checker Framework team does not currently have the resources to fix
performance problems, but we welcome community contributions.
Here are some reasons that the Checker Framework is slow.
It has to do all the same work as the compiler does, such as resolving
overloading and overriding, inferring generics, and type-checking.
Its analysis is general; it interprets user-defined type systems whereas
\<javac> hard-codes one type system and integrates it with other processing.
Its analysis are much richer. \<javac> can take certain shortcuts that
are not correct for all possible type systems.
It builds a control flow graph and performs a fixpoint analysis on it,
which \<javac> does not do.
It manipulates multiple representations of data, including \<javac>'s
internal representation, source code, control flow graph, and its own
internal representation. These transformations and lookups take time.
It switches between dataflow analysis and type analysis, and this
sometimes causes it to redo work.
When running a compound or aggregate checker, it computes the control
flow graph multiple times, and it makes multiple passes over the program
rather than just one.
\subsectionAndLabel{What does the Checker Framework version number mean?}{faq-version-number}
As explained in Section~\ref{version-number}, a change in the middle number
of the Checker Framework version string indicates a possible
Another policy is "semantic versioning" as defined at
\url{}. It is also a fine version number policy, with
its own advantages and disadvantages. It is a proposal, not a standard nor
an official definition. Some projects follow it, and many projects do not
follow it; even those that follow it often do so loosely. It does not
define key terms, such as "backwards compatible bug fixes". It includes an
escape hatch, ``Semantic Versioning is all about conveying meaning by how
the version number changes.''
% The API also includes the Annotation File Utilities.
If the Checker Framework strictly used's difinition, every
release would be a new major version, and the current version string would
% 70 releases as of the beginning of 2021.
around version 100.0.0.
Always incrementing the major version number would not convey meaning to
its users --- for example, it would not indicate major new functionality or
important behavior differences.
% The Checker Framework has over 10,000 methods in its API, xand most users
% depend on its external behavior which is also complex. The Checker
% Framework is released frequently.
\sectionAndLabel{Relationship to other tools}{faq-other-tools-section}
\subsectionAndLabel{Why not just use a bug detector (like SpotBugs or Error Prone)?}{faq-type-checking-vs-bug-detectors}
A pluggable type-checker
is a verification tool that prevents or detects all errors of a given
variety. If it issues no warnings, your code has no errors of a given
variety (for details about the guarantee, see
An alternate approach is to use a bug detector such as
\href{}{Error Prone},
or the
tools built into Eclipse (see Section~\ref{faq-eclipse}) and IntelliJ\@.
The \href{}{NullAway} and
\href{}{Eradicate} tools are more
like sound type-checking than bug detection, but all of those tools accept
unsoundness --- that is, false negatives or missed warnings --- in exchange
for analysis speed.
A pluggable type-checker or verifier
differs from a bug detector in several ways:
A type-checker reports \emph{all} errors in your code. If a type-checker
reports no warnings, then you have a guarantee (a proof) of correctness
A bug detector aims to find \emph{some} of the most obvious errors. Even
if a bug detector reports no warnings, there may still be errors in your
A type-checker requires you to annotate your code with type qualifiers,
or to run an inference tool that does so for you. That is, it requires
you to write a specification, then it verifies that your code meets its
Some bug detectors do not require annotations. This means that it may be
easier to get started running a bug detector. The tool makes guesses
about the intended behavior of your code, leading to false alarms or
missed alarms.
A verification tool may issue more warnings for a programmer to
investigate. Some bug detectors internally generate many warnings, then
use heuristics to discard some of them. The cost is missed alarms, when
the tool's heuristics classified the warnings as likely false positives
and discarded them.
A type-checker uses a more sophisticated and precise analysis. For
example, it can take advantage of method annotations and annotations on
generic type parameters, such as \code{List<@NonNull String>}. An
example specific to the Nullness Checker (Section~\ref{nullness-checker},
no other tool correctly handles map keys or initialization.
A bug detector does a more lightweight analysis. This means that a bug
detector usually runs faster, giving feedback to the programmer more
rapidly and avoiding slowdowns. Its analysis is often narrow, avoiding
properties that are tricky to reason about or that might lead to false
alarms. The cost is missed alarms, when analysis is too weak to find the
Neither type checking nor bug detection subsumes the other. A
type-checker finds problems that a bug detector cannot. A bug detector
finds problems that a type-checker does not: there is no need for the
type-checker to address style rules, when a bug detector is adequate.
If your code is important to you, it is advantageous to run both types of
For a case study that compared the nullness analysis of FindBugs
(equivalent to SpotBugs), Jlint,
PMD, and the Checker Framework, see section 6 of the paper
\href{}{``Practical pluggable types for Java''}~\cite{PapiACPE2008}.
The case study was on a well-tested program in daily use. The Checker
Framework tool found 8 nullness errors (that is, null pointer
dereferences). None of the other tools found any errors. A follow-up 10
years later found that Eclipse's nullness analysis found 0 of the errors,
and IntelliJ's nullness analyses found 3 of the errors, that the Nullness
Checker found.
\href{}{JSR 308}~\cite{JSR308-2008-09-12}
documentation also contains a discussion of related work.
\subsectionAndLabel{How does the Checker Framework compare with Eclipse's null analysis?}{faq-eclipse}
Eclipse comes with a
\href{\%2Forg.eclipse.jdt.doc.user\%2Ftasks\%2Ftask-using_null_annotations.htm}{null analysis} that
can detect potential null pointer errors in your code. Eclipse's built-in
analysis differs from the Checker Framework in several respects.
The Checker Framework's Nullness Checker
(see~\chapterpageref{nullness-checker}) is more precise: it does a deeper
semantic analysis, so it issues fewer false positives than Eclipse.
Eclipse's nullness analysis is missing many features that the Checker
Framework supports, such as handling of map keys, partially-initialized
objects, method pre- and post-conditions, polymorphism, and a powerful
dataflow analysis. These are essential for practical verification of
real-world code without poor precision.
Furthermore, Eclipse by default ignores unannotated code (even unannotated
parameters within a method that contains other annotations).
As a result, Eclipse is more useful for bug-finding than for verification,
and that is what the Eclipse documentation recommends.
% See heading "Interpretation of null annotations" under
Eclipse assumes by default that all code is multi-threaded, which cripples its local
type inference. (This default can be turned off, however.)
The Checker Framework allows the user to
specify whether code will be run concurrently or not via the
\<-AconcurrentSemantics> command-line option (see
The Checker Framework builds on javac, so it is easier to run in
integration scripts or in
environments where not all developers have installed Eclipse.
% It is possible to use ecj as one's compiler:
Eclipse handles only nullness properties and is not extensible, whereas the
Checker Framework comes with over 20 type-checkers (for a list,
see~\chapterpageref{introduction}) and is extensible to more properties.
There are also some benefits to Eclipse's null analysis.
It is faster than the Checker Framework, in part because it is less featureful.
It is built into Eclipse, so you do not have to add it to your build scripts.
Its IDE integration is tighter and slicker.
In a case study, the Nullness Checker found 9 errors in a program, and
Eclipse's analysis found 0.
\subsectionAndLabel{How does the Checker Framework compare with NullAway?}{faq-nullaway}
\href{}{NullAway} is a lightweight, unsound
type-checker whose aim is similar to that of the Nullness Checker
(\chapterpageref{nullness-checker}). For both tools, the user writes
nullness annotations, and then the tool checks them.
NullAway is faster than the Nullness Checker and requires fewer annotations.
NullAway is unsound: even if NullAway issues no warnings, your code might
crash with a null pointer exception. Two differences are that NullAway
makes unchecked assumptions about getter methods and NullAway assumes all
objects are always fully initialized. NullAway forces all generic
arguments to be non-null, which is not an unsoundness but is less flexible
than the Nullness Checker.
\subsectionAndLabel{How does the Checker Framework compare with the JDK's \<Optional> type?}{faq-optional}
JDK 8 introduced the \sunjavadoc{java.base/java/util/Optional.html}{\code{Optional}}
class, a container that is either empty or contains a non-null value.
The Optional Checker (see Chapter~\ref{optional-checker}) guarantees that
programmers use \<Optional> correctly.
Section~\ref{nullness-vs-optional} explains the relationship between
nullness and \<Optional> and the benefits of each.
\subsectionAndLabel{How does pluggable type-checking compare with JML?}{faq-jml}
\href{}{JML}, the Java Modeling
Language~\cite{LeavensBR2006:JML}, is a language for writing formal
\textbf{JML aims to be more expressive than pluggable type-checking.}
A programmer can write a JML specification that
describes arbitrary facts about program behavior. Then, the programmer can
use formal reasoning or a theorem-proving tool to verify that the code
meets the specification. Run-time checking is also possible.
By contrast, pluggable type-checking can express a more limited set of
properties about your program. Pluggable type-checking annotations are
more concise and easier to understand.
\textbf{JML is not as practical as pluggable type-checking.}
The JML toolset is less mature. For instance, if your code uses
generics or other features of Java 5, then you cannot use JML.
However, JML has a run-time checker, which the Checker Framework currently
\subsectionAndLabel{Is the Checker Framework an official part of Java?}{faq-checker-framework-part-of-java}
The Checker Framework is not an official part of Java.
The Checker Framework relies on type annotations, which became part of Java
with Java 8 (released in March 2014). For more about type annotations, see the
Annotations (JSR 308) FAQ} for more details.
\subsectionAndLabel{What is the relationship between the Checker Framework and JSR 305?}{faq-jsr-305}
JSR 305 aimed to define official Java names for some annotations, such as
\<@NonNull> and \<@Nullable>. However, it did not aim to precisely define
the semantics of those annotations nor to provide a reference
implementation of an annotation processor that validated their use;
as a result, JSR 305 was of limited utility as a specification.
JSR 305 has been abandoned; there has been
no activity by its expert group since
% January
By contrast, the Checker Framework precisely defines the meaning of a set
of annotations and provides powerful type-checkers that validate them.
However, the Checker Framework is not an official part of the Java
language; it chooses one set of names, but another tool might choose other
In the future, the Java Community Process might revitalize JSR 305 or
create a replacement JSR to standardize the names and
meanings of specific annotations, after there is more experience with their
use in practice.
% JSR 305 didn't specify the semantics of its annotations, and where it did
% they were idiosyncratic --- essentially mimicking the FindBugs tool, but
% not useful for any other defect detection tool. A revitalization of JSR
% 305 would have to start over from scratch in order to clearly specify a
% semantics that is general and useful for a whole range of tools.
% The Java community does not yet understand all the subtleties well enough
% to set the annotations in stone in the Java specification yet; it is
% better for the community to experiment with different approaches, such as
% those of FindBugs, IntelliJ, Eclipse, and the Checker Framework, so that
% we can come to consensus before deciding on an official set.
The Checker Framework defines annotations \<@NonNull> and \<@Nullable> that
are compatible with annotations defined by JSR 305, SpotBugs, IntelliJ, and
other tools; see Section~\ref{nullness-related-work}.
\subsectionAndLabel{What is the relationship between the Checker Framework and JSR 308?}{faq-jsr-308}
JSR 308, also known as the Type Annotations specification, dictates the
syntax of type annotations in Java SE 8: how they are expressed in the
Java language.
JSR 308 does not define any type annotations such as \<@NonNull>, and it does
not specify the semantics of any annotations. Those tasks are left to
third-party tools. The Checker Framework is one such tool.
% LocalWords: toolset AbstractCollection ConcurrentHashMap NullnessUtil
% LocalWords: castNonNull createWidget backporting JCIP's GuardedBy Awarns PMD
% LocalWords: ElementType nullness bytecodes Jlint Hashtable SuppressWarnings
% LocalWords: RegexUtil compareTo myA requiresB nullable java myobject
% LocalWords: multithreading myfield Regex NonEmpty Xmaxerrs Xmaxwarns
% LocalWords: MonotonicNonNull EnsuresNonNull myFieldName pre dev API's
% LocalWords: m1 m2 RequiresNonNull AconcurrentSemantics MyQual plugin
% LocalWords: MyClass MyMoreRestrictiveQual TOPTYPEANNO DEFAULTANNO api
%% LocalWords: OtherClass Goetz antipattern subclassed varargs regexes
%% LocalWords: featureful RetentionPolicy instanceof contravariance qual
%% LocalWords: NoSuchElementException binarySearch subclasses faq awarns
%% LocalWords: intExample1 intExample2 requiresPositive RUNTIME NullAway
%% LocalWords: IllegalFormatException typequals typedef runtime nullaway
%% LocalWords: covariance InheritedAnnotation someMethod jml jsr Java''
% LocalWords: checkers'' covariance'' contravariance'' Xmx3g lookups