# 什么是类型注解

提示

注解大家都知道,从java5开始加入这一特性,发展到现在已然是遍地开花,在很多框架中得到了广泛的使用,用来简化程序中的配置。那充满争议的类型注解究竟是什么? 复杂还是便捷?

  1. 在java 8之前,注解只能是在声明的地方所使用,比如类,方法,属性;
  2. java 8里面,注解可以应用在任何地方,比如:
    创建类实例
new @Interned MyObject();
    
1
2

类型映射

myString = (@NonNull String) str;
1

implements 语句中

class UnmodifiableList<T> implements @Readonly List<@Readonly T> {}
    
1
2

throw exception声明

void monitorTemperature() throws @Critical TemperatureException {}
1

需要注意的是,类型注解只是语法而不是语义,并不会影响java的编译时间,加载时间,以及运行时间,也就是说,编译成class文件的时候并不包含类型注解

# 类型注解的作用

先看看下面代码

Collections.emptyList().add("One");
int i=Integer.parseInt("hello");
System.console().readLine();
1
2
3

上面的代码编译是通过的,但运行是会分别报UnsupportedOperationException; NumberFormatException;NullPointerException异常,这些都是runtime error
check framework是第三方工具,配合Java的类型注解效果就是1+1>2。它可以嵌入到javac编译器里面,可以配合ant和maven使用, 地址是http://types.cs.washington.edu/checker-framework/。 check framework可以找到类型注解出现的地方并检查,举个简单的例子:

import checkers.nullness.quals.*;
public class GetStarted {
    void sample() {
        @NonNull Object ref = new Object();
    }
}  
1
2
3
4
5
6

使用javac编译上面的类

javac -processor checkers.nullness.NullnessChecker GetStarted.java  
1

编译是通过,但如果修改成

@NonNull Object ref = null;    
1

再次编译,则出现

GetStarted.java:5: incompatible types.
found   : @Nullable <nulltype>
required: @NonNull Object
        @NonNull Object ref = null;
                              ^
1 error
    
1
2
3
4
5
6
7

# 类型注解向下兼容的解决方案

如果你不想使用类型注解检测出来错误,则不需要processor,直接javac GetStarted.java是可以编译通过的,这是在java 8 with Type Annotation Support版本里面可以,但java 5,6,7版本都不行,因为javac编译器不知道@NonNull是什么东西,但check framework 有个向下兼容的解决方案,就是将类型注解nonnull用/**/注释起来,比如上面例子修改为

import checkers.nullness.quals.*;
public class GetStarted {
    void sample() {
        /*@NonNull*/ Object ref = null;
    }
}  
1
2
3
4
5
6

这样javac编译器就会忽略掉注释块,但用check framework里面的javac编译器同样能够检测出nonnull错误。 通过类型注解+check framework我们可以看到,现在runtime error可以在编译时候就能找到。