注解实现自定义IDE语法检查规则替代枚举常量

258 阅读2分钟

注解学习通道:Java —— 注解(Annotation)

1. IDE语法检查

IDE语法检查是注解在RetentionPolicy.SOURCE时的应用。

IDE语法检查:集成开发环境(Integrated Development EnvironmentIDE)在编写代码的过程中进行的一种静态代码分析。

注:静态代码分析是指在不实际执行程序的情况下,对代码语义和行为进行分析,由此找出程序中由于错误的编码导致异常的程序语义或未定义的行为。

IDE语法检查目的:在代码编辑阶段就能够检测和提示可能存在的语法错误等潜在的问题,从而提高代码的质量、可读性和可维护性。

Q:那么语法检查是由谁实现的?

A:是IDE实现的,IDE插件实现的。

2. @DrawableRes

在项目中,我们一定遇到过下述类似场景:

设置资源文件,需要传入资源id,资源id为 int 类型,所以方法参数为int id

public static void setDrawable(int id){
}
public static void main(String[] args) {
    setDrawable(1);
}

以上代码并没有报错,但我们本意是想传一个资源 id,一般为 R.drawable 开头的 id,并不是一个数字。

这种情况可以在参数前使用 @DrawableRes(androidx 定义的注解),此时若再传入数字就会提供语法检查:

image.png

@DrawableRes 是 androidx 已经定义好的语法检测规则。

我们可以使用元注解 @IntDef@StringDef 定义我们自己的语法检测规则。

@IntDef 自定义语法规则替代枚举

androidx.annotation 中提供 @IntDef 注解,此注解定义如下:

@Retention(SOURCE)   // 源码级别注解
@Target({ANNOTATION_TYPE})
public @interface IntDef {
    int[] value() default {};
    
    boolean flag() default false;

    boolean open() default false;
}

@IntDef 元注解作用是提供语法检查

举一个例子,Java中一个普遍的操作,设计设置状态接口,使用枚举存不同的状态:

public class Test {

    private static Status mCurrentStatus;
    
    enum Status{
        YELLOW, RED, GREEN
    }
    
    public static void setCurrentStatus(Status currentStatus){
        mCurrentStatus = currentStatus;
        
    }
    public static void main(String[] args) {
        setCurrentStatus(Status.GREEN); // 传递枚举类型
    }
}

枚举中每一个元素都是一个对象,占用内存较大,枚举类型比较占用内存:

image.png

这时可能使用常量代替枚举类型,此时定义注解 @Status,并使用元注解 @IntDef 限定类型范围,如输入不是YELLOW, RED, GREEN其中之一,则会给出提示。

public class Test {
    @Status
    private static int mCurrentStatus;
    public static final int YELLOW = 0;
    public static final int RED = 1;
    public static final int GREEN = 2;
    
    @IntDef({YELLOW, RED, GREEN})  // 限定类型范围
    @Target({ElementType.FIELD, ElementType.PARAMETER})  // 源码级别
    @Retention(RetentionPolicy.SOURCE)
    @interface Status{

    }

    public static void setCurrentStatus(@Status int currentStatus){
        mCurrentStatus = currentStatus;

    }
    public static void main(String[] args) {
        setCurrentStatus(1);  // 会有红线提示
    }
}