The Java 8 type annotations (JSR 308) allow type checkers to perform static code analysis. For example, The Checker Framework can check for possible nullness via
This is a good question.
For the purpose of static checking at compile time,
CLASS retention would be sufficient. Note that
SOURCE 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.
The annotation designers used
RUNTIME retention to permit tools to perform run-time operations. This could include checking the annotations (like an assert statement), type-checking of dynamically-loaded code, checking of casts and
instanceof operations, resolving reflection more precisely, and more. Not many such tools exist today, but the annotation designers wanted to accommodate them in the future.
You remarked that with
@Retention(RetentionPolicy.CLASS), "the code does not have any runtime dependencies on the respective library." This is actually true with
@Retention(RetentionPolicy.RUNTIME), too! See this Stack Overflow question:
Why doesn't a missing annotation cause a ClassNotFoundException at runtime? .
In summary, using
CLASS retention costs a negligible amount of space at run time, enables more potential uses in the future, and does not introduce a run-time dependency.
In the case of the Checker Framework, it offers run-time tests such as
isRegex(String). If your code uses such methods, your code will be dependent on the Checker Framework runtime library (which is smaller than the entire Checker Framework itself).