Java 8——重複註解和註解的做用範圍的擴大化

一.重複註解

在某些狀況下,但願將相同的註解應用於聲明或類型用途。從Java SE 8發行版開始,重複註解使能夠執行此操做。html

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

@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註解中。oracle

將相同的註解應用於聲明而不首先聲明它是可重複的,這會致使編譯時錯誤。框架

第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

相關文章
相關標籤/搜索