Java注解改变了编程的体验!

前言

很长一段时间以来,Java通过在其源代码中使用Javadoc注释标签,从而支持一种有限的元数据。使用@deprecated或@author这样的Javadoc标签,我们可以向一个类、方法或字段添加一些信息,具体方法是将信息放入到这些项上面的注释中。在这种情况下,这些信息主要对Javadoc文档的生成器有用,因为注释只存在于Java源代码中。然而,开发者很长时间以来期望一种方式能够生成元数据以用于其他的目的。实际上,有些工具已经开发了很长一段时间了,它们可以读取注释中的各种Javadoc式的标签,并且用它们做各种各样的事情,包括代码生成和文档。在Java 5.0中,有一种叫作注解的正式的、可扩展的元数据系统添加到了语言中,它提供这种源代码层级的功能,以及在运行时使用元数据的新功能。

基本语法

如下是一个注解的定义。注解的定义看起来很像接口的定义。

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
    
}

注解放置在代码中,其前面有注解项,注解项使用一个@ 符号,后面跟着注解的类名。除了 @ 符号之外, @Idempotent 的定义看起来更像一个空接口。注解的定义也需要一些元注解(meta-annoation),比如 @Target 和 @Retention。@Target 定义你的注解可以应用在哪里(例如是方法还是字段)。@Retention 定义了注解在哪里可用,在源代码中(SOURCE),class文件(CLASS)中或者是在运行时(RUNTIME)。不包含任何元素的注解称为标记注解(marker annotation),例如上例中的 @Idempotent 就是标记注解。

下面是一个简单的注解。程序员可以使用该注解来标注满足特定用例的一个方法或者一组方法。而开发者在维护项目时可以轻松的找到用例用于更新,或者他们可以调试系统中业务逻辑。

package com.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
    /**
     * 幂等名称,作为redis缓存Key的一部分。
     */
    String value();

    /**
     * 幂等过期时间(秒),即:在此时间段内,对API进行幂等处理。
     */
    long expireMillis() default 5;
}

注意 value和 expireMillis 与方法定义类似。由于编译器会对 value 进行类型检查,因此将跟踪数据库与用例文档和源代码相关联是可靠的方式。expireMillis 元素拥有一个 default 值,如果在注解某个方法时没有给出 expireMillis 的值。则该注解的处理器会使用此元素的默认值。

在下面的类中,有三个方法被注解为用例:

package com.annotation;

public class Test {

    @Idempotent(value = "test1")
    public void test1() {

    }

    @Idempotent(value = "test2", expireMillis = 10)
    public void test2() {

    }

}

注解的元素在使用时表现为 名-值 对的形式,并且需要放置在 @Idempotent 声明之后的括号内。在 test1() 方法的注解中,并没有给出 description 的值,所以在 @interface Idempotent 的注解处理器分析处理这个类的时候会使用该元素的默认值。

注解不支持继承

你不能使用 extends 关键字来继承 @interfaces。如果支持继承,就会大大减少打字的工作量并且使得语法更整洁。在 Java 的未来版本中,似乎没有任何关于让注解支持继承的提案。

标准注解

注解是Java 5中的一个新特性,最初有3个标准注解:Override、Deprecated和SupressWarnings,它们都定义在java.lang包中。

  • Override

是一种标记注解类型,可应用于方法,它告诉编译器该方法是超类中一个方法的覆盖。这个注解类型可以防止程序员在覆盖方法时出错。

  • Deprecated

是一个标记注解类型,可应用于某个方法或某个类型,表示该方法或该类型已被弃用。被弃用的方法或类型由程序员标记,以警告编写代码的用户不应使用或覆盖该方法以及使用或扩展该类型。

  • SuppressWarnings

表示编译器应该针对注解的类或方法,抑制指定的警告类型。

元注解

Java 语言中目前有 5 种标准注解(前面介绍过),以及 5 种元注解。元注解用于注解其他的注解
Java注解改变了编程的体验!_第1张图片

大多数时候,程序员定义自己的注解,并编写自己的处理器来处理他们。

自定义注解

编译器对于元素的默认值有些过于挑剔。首先,元素不能有不确定的值。也就是说,元素要么有默认值,要么就在使用注解时提供元素的值。

这里有另外一个限制:任何非基本类型的元素, 无论是在源代码声明时还是在注解接口中定义默认值时,都不能使用 null 作为其值。这个限制使得处理器很难表现一个元素的存在或者缺失的状态,因为在每个注解的声明中,所有的元素都存在,并且具有相应的值。为了绕开这个约束,可以自定义一些特殊的值,比如空字符串或者负数用于表达某个元素不存在。

// annotations/SimulatingNull.java
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    int id() default -1;
    String description() default "";
}

这是一个在定义注解的习惯用法。

总结

注解是 Java 引入的一项非常受欢迎的补充,它提供了一种结构化,并且具有类型检查能力的新途径,从而使得你能够为代码中加入元数据,而且不会导致代码杂乱并难以阅读。Java 提供了很少的内置注解。这意味着如果你在别处找不到可用的类库,那么就只能自己创建新的注解以及相应的处理器。

最后的最后

为初学者提供学习指南,为从业者提供参考价值。我坚信码农也具有产生洞见的能力。扫描下图二维码关注,学习和交流!

你可能感兴趣的:(java)