Java 8——重復注解和注解的作用范圍的擴大化


一.重復注解

在某些情況下,希望將相同的注解應用於聲明或類型用途。從Java SE 8發行版開始,重復注解使可以執行此操作。

例如,正在編寫代碼以使用計時器服務,該服務使能夠在給定時間或某個計划上運行方法,類似於UNIX cron服務。現在,要設置計時器以在該月的最后一天和每個星期五晚上11:00 運行方法doPeriodicCleanup。要設置要運行的計時器,請創建一個@Schedule注解並將其應用於doPeriodicCleanup方法兩次。第一次使用指定月份的最后一天,第二次使用指定星期五晚上11點,如下面的代碼示例所示:

@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }

前面的示例將注解應用於方法。可以在使用標准注解的任何位置重復注解。例如,有一個用於處理未授權訪問異常的類。使用一個@Alert注解為管理員注解並為管理員添加另一個注解:

@Alert(role="Manager")
@Alert(role="Administrator")
public class UnauthorizedAccessException extends SecurityException { ... }

出於兼容性原因,重復注解存儲在由Java編譯器自動生成的容器注解中。為了使編譯器執行此操作,代碼中需要兩個聲明。

第1步:聲明可重復的注解類型
注解類型必須使用@Repeatable元注解標記。以下示例定義自定義@Schedule可重復注解類型:

import java.lang.annotation.Repeatable;

@Repeatable(Schedules.class)
public @interface Schedule {
  String dayOfMonth() default "first";
  String dayOfWeek() default "Mon";
  int hour() default 12;
}

@Repeatable括號 中的元注解的值是Java編譯器為存儲重復注解而生成的容器注解的類型。在此示例中,包含注解類型是Schedules,因此重復@Schedule注解存儲在@Schedules注解中。

將相同的注解應用於聲明而不首先聲明它是可重復的,這會導致編譯時錯誤。

第2步:聲明包含注解類型
包含注解類型必須具有value帶數組類型的元素。數組類型的組件類型必須是可重復的注解類型。Schedules包含注解類型的聲明如下:

public @interface Schedules {
    Schedule[] value();
}

1.檢索注解

Reflection API中有幾種可用於檢索注解的方法。返回單個注解的方法(例如 AnnotatedElement.getAnnotation(Class ))的行為未更改,因為如果存在所請求類型的一個注解,它們僅返回單個注解。如果存在多個所請求類型的注解,則可以通過首先獲取其容器注解來獲取它們。通過這種方式,遺留代碼繼續工作。Java SE 8中引入了其他方法,它們掃描容器注解以一次返回多個注解,例如 AnnotatedElement.getAnnotationsByType(Class )。請參閱 AnnotatedElement 有關所有可用方法的信息的類規范。

2.設計注意事項

設計注解類型時,必須考慮該類型注解的基數。現在可以使用注解零次,一次,或者,如果注解的類型被標記為@Repeatable多次,則不止一次。還可以通過使用@Target元注解來限制可以使用注解類型的位置。例如,可以創建只能在方法和字段上使用的可重復注解類型。仔細設計注解類型非常重要,以確保使用注解的程序員發現它盡可能靈活和強大。

二.類型注解和可插入類型系統

在Java SE 8發行版之前,注解只能應用於聲明。從Java SE 8發行版開始,注解也可以應用於任何類型的使用。這意味着可以在任何使用類型的地方使用注解。使用where類型的一些示例是類實例創建表達式(new),強制轉換,implements子句和throws子句。

  • 創建實例表達式時
new @Interned MyObject();
  • 類型轉換:
myString = (@NonNull String) str;
  • 實現時:
class UnmodifiableList<T> implements
      @Readonly List<@Readonly T> { ... }
  • 聲明拋出異常:
void monitorTemperature() throws
        @Critical TemperatureException { ... }

在元注解@Target中增加了作用類型:

/**
 * Type parameter declaration
 *
 * @since 1.8
 */
TYPE_PARAMETER,

/**
 * Use of a type
 *
 * @since 1.8
 */
TYPE_USE

創建類型注解是為了支持改進的Java程序分析,以確保更強的類型檢查。Java SE 8版本不提供類型檢查框架,但它允許編寫(或下載)類型檢查框架,該框架實現為與Java編譯器結合使用的一個或多個可插入模塊。

例如,希望確保程序中的特定變量永遠不會分配給null; 你想避免觸發一個NullPointerException。可以編寫自定義插件來檢查此問題。然后,將修改代碼以注解該特定變量,表明它從未分配給null。變量聲明可能如下所示:

@NonNull String str;

當編譯代碼(包括NonNull命令行中的模塊)時,編譯器會在檢測到潛在問題時輸出警告,允許修改代碼以避免錯誤。在更正代碼以刪除所有警告后,程序運行時不會發生此特定錯誤。

可以使用多個類型檢查模塊,其中每個模塊檢查不同類型的錯誤。通過這種方式,可以在Java類型系統的基礎上構建,在希望的時間和地點添加特定的檢查。

通過明智地使用類型注解和可插入類型檢查器的存在,可以編寫更強大且更不容易出錯的代碼。

在許多情況下,不必編寫自己的類型檢查模塊。有第三方為你完成了這項工作。例如,可能希望利用華盛頓大學創建的Checker Framework。該框架包括一個NonNull模塊,一個正則表達式模塊和一個互斥鎖模塊。有關更多信息,請參閱 Checker Framework。

參考

Repeating Annotations
Type Annotations and Pluggable Type Systems


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM