【JDK8】Annotation 功能增強
在 JDK8 出現之前, JDK8 的 public class MailBox<@Email T> { ... } 那麼,你在定義 package cc.openhome; import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Target(ElementType.TYPE_PARAMETER) public @interface Email {}
package cc.openhome; import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Target(ElementType.TYPE_USE) public @interface Test {} 那以下幾個標註範例都是可以的: List<@Test Comparable> list1 = new ArrayList<>(); List<? extends Comparable> list2 = new ArrayList<@Test Comparable>(); @Test String text; text = (@Test String) new Object(); java.util. @Test Scanner console; console = new java. util. @Test11 Scanner(System.in); 注意,這幾個範例都僅對 @Test java.lang.String text; 上面這個例子中, 可以在更多地方標註,一些靜態分析工具或框架是最主要受到影響的對象,舉例來說,The Checker Framework 中有個 ... @Retention(value=RUNTIME) @Target(value={TYPE_USE,TYPE_PARAMETER}) public @interface NonNull ... 你可以 下載 The Checker Framework,撰寫本文的時間點它是 1.8.1 版,下載完成後解開 zip 檔案,並設置環境變數:
最主要的是,你的 package cc.openhome; import org.checkerframework.checker.nullness.qual.*; public class GetStarted { public static void main() { java.util.@NonNull List<String> elems = new java.util.ArrayList<>(); } } 這個簡單的程式使用了
程式中的 java.util.@NonNull List<String> elems = null; 使用相同指令編譯時,就會發生以下編譯錯誤: error: [assignment.type.incompatible] incompatible types in assignment. java.util.@NonNull List<String> elems = null; ^ found : null required: @UnknownInitialization @NonNull List<@Initialized @NonNull String> 1 error 可以看到,對於 package cc.openhome; import org.checkerframework.checker.nullness.qual.*; import java.util.*; public class GetStarted { public static void main(String[] args) { List<String> elems = new ArrayList<>(); elems.add(null); } } 使用相同指令編譯,預設會檢查出被加入 error: [argument.type.incompatible] incompatible types in argument. elems.add(null); ^ found : null required: @Initialized @NonNull String 1 error 如果你真的想允許 List<@Nullable String> elems = new ArrayList<>(); elems.add(null); 想要知道更多 Checker 的使用,可以參考The Checker Framework Manual。 JDK8 除了 public @interface Filter { String[] value(); } 這可以讓你如下進行標註: @Filter({"/admin", "/manager"}) public interface SecurityFilter { ... } 如果你想要另一種如下的標註風格: package cc.openhome; @Filter("/admin") @Filter("/manager") public interface SecurityFilter {} 在 JDK8 還沒出現之前,沒有辦法達到這點需求,如果使用 JDK8,可以如下定義 package cc.openhome; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Repeatable(Filters.class) public @interface Filter { String value(); } @Retention(RetentionPolicy.RUNTIME) @interface Filters { Filter[] value(); } 實際上這是編譯器的把戲,在這邊你使用 JDK8 在 package cc.openhome; import static java.lang.System.out; public class SecurityTool { public static void main(String[] args) { Filter[] filters = SecurityFilter.class. getAnnotationsByType(Filter.class); for(Filter filter : filters) { out.println(filter.value()); } out.println(SecurityFilter.class.getAnnotation(Filter.class)); } } 執行結果如下,可以觀察到,對於被標註為 /admin /manager null |