The Checker Framework – Pluggable Type Systems for Java – The Checker Framework – Java的可插拔类型系统

最后修改: 2018年 3月 1日

1. Overview


From the Java 8 release onwards, it’s possible to compile programs using the so-called Pluggable Type Systems – which can apply stricter checks than the ones applied by the compiler.

Java 8版本开始,可以使用所谓的Pluggable Type Systems来编译程序–它可以应用比编译器应用更严格的检查。

We only need to use the annotations provided by the several Pluggable Type Systems available.


In this quick article, we’ll explore the Checker Framework, courtesy of the University of Washington.


2. Maven


To start working with the Checker Framework, we need to first add it into our pom.xml:



The latest version of the libraries can be checked on Maven Central.

库的最新版本可以在Maven Central上查看。

The first two dependencies contain the code of The Checker Framework while the latter is a custom version of the Java 8 classes, in which all types have been properly annotated by the developers of The Checker Framework.

前两个依赖包含The Checker Framework的代码,而后者是Java 8类的自定义版本,其中所有类型都被The Checker Framework的开发者正确注释了。

We then have to properly tweak the maven-compiler-plugin to use The Checker Framework as a pluggable Type System:

然后我们必须适当调整maven-compiler-plugin,将The Checker Framework作为可插入的Type System


The main point here is the content of the <annotationProcessors> tag. Here we listed all the checkers that we want to run against our sources.


3. Avoiding NullPointerExceptions


The first scenario in which The Checker Framework can help us is identifying the piece of codes where a NullPoinerException could originate:


private static int countArgs(@NonNull String[] args) {
    return args.length;

public static void main(@Nullable String[] args) {

In the above example, we declared with the @NonNull annotation that the args argument of countArgs() has to be not null.


Regardless of this constraint, in main(), we invoke the method passing an argument that can indeed be null, because it’s been annotated with @Nullable.


When we compile the code, The Checker Framework duly warns us that something in our code could be wrong:


[WARNING] /checker-plugin/.../[12,38] [argument.type.incompatible]
 incompatible types in argument.
  found   : null
  required: @Initialized @NonNull String @Initialized @NonNull []

4. Proper Use of Constants as Enumerations


Sometimes we use a series of constants as they were items of an enumeration.


Let’s suppose we need a series of countries and planets. We can then annotate these items with the @Fenum annotation to group all the constants that are part of the same “fake” enumeration:

假设我们需要一系列的国家和行星。然后我们可以用@Fenum注解对这些项目进行注解,将所有属于同一 “假 “枚举的常量分组。

static final @Fenum("country") String ITALY = "IT";
static final @Fenum("country") String US = "US";
static final @Fenum("country") String UNITED_KINGDOM = "UK";

static final @Fenum("planet") String MARS = "Mars";
static final @Fenum("planet") String EARTH = "Earth";
static final @Fenum("planet") String VENUS = "Venus";

After that, when we write a method that should accept a String that is a “planet”, we can properly annotate the argument:

之后,当我们写一个应该接受一个 “星球 “的字符串的方法时,我们可以正确地注释参数。

void greetPlanet(@Fenum("planet") String planet){
    System.out.println("Hello " + planet);

By error, we can invoke greetPlanet() with a string that hasn’t been defined as being a possible value for a planet, such:


public static void main(String[] args) {

The Checker Framework can spot the error:


[WARNING] /checker-plugin/.../[29,26] [argument.type.incompatible]
 incompatible types in argument.
  found   : @Fenum("country") String
  required: @Fenum("planet") String

5. Regular Expressions


Let’s suppose we know a String variable has to store a regular expression with at least one matching group.


We can leverage the Checker Framework and declare such variable like that:


@Regex(1) private static String FIND_NUMBERS = "\\d*";

This is obviously a potential error because the regular expression we assigned to FIND_NUMBERS does not have any matching group.


Indeed, the Checker Framework will diligently inform us about our error at compile time:


[WARNING] /checker-plugin/.../[7,51] [assignment.type.incompatible]
incompatible types in assignment.
  found   : @Regex String
  required: @Regex(1) String

6. Conclusion


The Checker Framework is a useful tool for developers that want to go beyond the standard compiler and improve the correctness of their code.


It’s able to detect, at compile time, several typical errors that can usually only be detected at runtime or even halt compilation by raising a compilation error.


There’re many more standard checks than what we covered in this article; check out the checks available in The Checker Framework official manual here, or even write your own.


As always, the source code for this tutorial, with some more examples, can be found over on GitHub.