Java @SuppressWarnings 詳解

背景知識:
從JDK5開始提供名爲Annotation(註釋)的功能,它被定義爲JSR-175規範。註釋是以“@註釋名”在代碼中存在的,還可以添加一些參數值,例如:@SuppressWarnings(value=”unchecked”)。註釋可以附加在package, class, method, field等上面,相當於給它們添加了額外的輔助信息,我們可以通過反射機制編程實現對這些元數據的訪問。如果沒有外部解析工具等對其加以解析和處理的情況,本身不會對Java的源代碼或class文件等產生任何影響,也不會對它們的執行產生任何影響。
元數據的作用,大致可分爲三種:編寫文檔,通過代碼裏標識的元數據生成文檔;代碼分析,通過代碼裏標識的元數據對代碼進行分析;編譯檢查,通過代碼裏標識的元數據讓編譯器能實現基本的編譯檢查。

JDK5內置的基本註釋
JDK5內置了一些常用的註釋,可以在編譯時幫我們捕獲部分編譯錯誤,及提示信息,下面介紹下這些註釋的用法:

1、@Override定義在java.lang.Override中,此註釋只適用於修辭方法,表示一個方法聲明打算重寫超類中的另一個方法聲明。如果方法利用此註釋類型進行註解但沒有重寫超類方法,則編譯器會生成一條錯誤消息。例如我們爲某類重寫toString()方法卻寫成了tostring(),並且我們爲該方法添加了@Override註釋;代碼如下:

1 public class OverrideDemo {
2     @Override
3 public String tostring() {
4         return super.toString();
5     }
6 }

在編譯時,會提示以下錯誤信息:

OverrideTest.java:4: 方法未覆蓋其父類的方法
@Override
^1 錯誤

2、@Deprecated定義在java.lang.Deprecated中,此註釋可用於修辭方法、屬性、類,表示不鼓勵程序員使用這樣的元素,通常是因爲它很危險或存在更好的選擇。在使用不被贊成的程序元素或在不被贊成的代碼中執行重寫時,編譯器會發出警告。使用@Deprecated的示例代碼如下:

1 public class DeprecatedDemo {
2     public static void main(String[] args) {
3          DeprecatedClass.DeprecatedMethod();
4     }
5 }
6  
7 class DeprecatedClass {
8     @Deprecated
9     public static void DeprecatedMethod() {
10         // TODO
11     }
12 }

在編譯時,會得到以下提示信息:

注意:DeprecatedDemo.java 使用或覆蓋了已過時的 API。
注意:要了解詳細信息,請使用 -Xlint:deprecation 重新編譯。

如果在編譯時添加-Xlint:deprecation參數,我們能更清楚的看到該警告的詳細信息,如下:

DeprecatedDemo.java:6: 警告:[deprecation] SomeClass 中的 DeprecatedMethod() 已過時
SomeClass.DeprecatedMethod();
^1 警告

要注意@Deprecated與@deprecated的區別,@deprecated是爲了生成文檔的需要,例如:

1 class DeprecatedClass {
2         /**
3 * @deprecated  此方法已過時,不建議使用
4 */
5 @Deprecated
6     public static void DeprecatedMethod() {
7         // TODO
8     }
9 }

3、@SuppressWarnings定義在java.lang.SuppressWarnings中,用來抑制編譯時的警告信息。與前兩個註釋有所不同,你需要添加一個參數才能正確使用,這些參數值都是已經定義好了的,我們選擇性的使用就好了,參數如下:

通過上面的表格,你應該瞭解到每個參數的用意了,下面我就以一個常用的參數unchecked爲例,爲你展示如何使用@SuppressWarnings註釋,示例代碼如下:

1 import java.util.List;
2 import java.util.ArrayList;
3 public class SuppressWarningsDemo {
4         public static List cache = new ArrayList();
5         //@SuppressWarnings(value = "unchecked")
6         public void add(String data) {
7             cache.add(data);
8         }
9 }

當我們不使用@SuppressWarnings註釋時,編譯器就會有如下提示:

注意:SuppressWarningsDemo.java 使用了未經檢查或不安全的操作。
注意:要了解詳細信息,請使用 -Xlint:unchecked 重新編譯。

下面我們去掉@SuppressWarnings(value=”unchecked”)這一行的註釋符“//”,它會屏蔽編譯時的警告信息,這也就是它所要達到的目的。
另外,由於@SuppressWarnings註釋只有一個參數,並且參數名爲value,所以我們可以將上面一句註釋簡寫爲
@SuppressWarnings(“unchecked”);
同時參數value可以取多個值如:
@SuppressWarnings(value={“unchecked”, “deprecation”})
或@SuppressWarnings({“unchecked”, “deprecation”})。

自定義Annotation註釋

1、註釋annotation與接口的異同:
因爲annotation類型是一個非凡的接口,所以它與接口之間存在着某些差異:

A. Annotation類型使用關鍵字@interface而不是interface,這個關鍵字聲明隱含了一個信息,它是繼承了java.lang.annotation.Annotation接口,並非聲明瞭一個interface。

B. Annotation類型的方法定義是獨特的、受限制的,方法必須聲明爲無參數、無異常拋出的。這些方法定義了annotation的成員:方法名成爲了成員名,而方法返回值成爲了成員的類型。而方法返回值類型必須爲primitive類型、Class類型、枚舉類型、annotation類型或者由前面類型之一作爲元素的一維數組。方法的後面可以使用default和一個默認數值來聲明成員的默認值,null不能作爲成員默認值,這與我們在非annotation類型中定義方法有很大不同。

C. Annotation類型又與接口有着近似之處,它們可以定義常量、靜態成員類型(比如枚舉類型定義)。Annotation類型也可以如接口一般被實現或者繼承。

2、自定義註釋的實例:
下面,我們將看到如何定義annotation類型的例子。它展示了annotation類型聲明以及

1 @interfaceinterface之間的不同:
2  
3 import java.lang.annotation.*;
4 /**
5 * 使用annotation來描述那些被標註的成員是不穩定的,需要更改
6 */
7 public @interface Unstable {
8 }

下面的另一個例子只定義了一個成員。並通過將這個成員命名爲value,使我們可以方便的使用這種annotation的快捷聲明方式:

1 /**
2 * 使用Author這個annotation定義在程序中指出代碼的作者
3 */
4 public @interface Author {
5       /** 返回作者名 */
6       String value();
7 }

以下的例子更加複雜。Reviews annotation類型只有一個成員,但是這個成員的類型是複雜的:由Review annotation組成的數組。Review annotation類型有3個成員:枚舉類型成員grade、表示Review名稱的字符串類型成員Reviewer、具有默認值的字符串類型成員 Comment。

1 /**
2 * Reviews annotation類型只有一個成員,
3 * 但是這個成員的類型是複雜的:由Review annotation組成的數組
4 */
5 @Retention(RetentionPolicy.RUNTIME)
6 public @interface Reviews {
7     Review[] value();
8 }
9 /**
10 * Review annotation類型有3個成員:
11 * 枚舉類型成員grade、
12 * 表示Review名稱的字符串類型成員Reviewer、
13 * 具有默認值的字符串類型成員Comment。
14 */
15 public @interface Review {
16     // 內嵌的枚舉類型
17      public static enum Grade { EXCELLENT, SATISFACTORY, UNSATISFACTORY };
18      // 下面的方法定義了annotation的成員
19      Grade grade();
20      String reviewer();
21      String comment() default "";
22 }

最後,我們來定義一個annotation方法用於羅列出類運行中所有的unchecked異常。這個 annotation類型將一個數組作爲了唯一的成員。數組中的每個元素都是異常類。爲了加強對未檢查的異常(此類異常都是在運行時拋出)進行報告,我們可以在代碼中對異常的類型進行限制:

1 public @interface UncheckedExceptions {
2      Class[] value();
3 }

Meta-Annotation類型:

Annotation 類型可以被它們自己所標註。Java5.0定義了4個標準的meta-annotation類型,分別是:Target、Retention、Documented、Inherited,它們被用來提供對其它annotation類型作說明。 這些類型和它們所支持的類在java.lang.annotation包中可以找到。

@Target的用法:指示註釋類型所適用的程序元素的種類。如果註釋類型聲明中不存在 Target 元註釋,則聲明的類型可以用在任一程序元素上。如果存在這樣的元註釋,則編譯器強制實施指定的使用限制。 例如,以下這個註釋只能用來聲明方法:

1 @Target(ElementType.METHOD)
2   public @interface MyAnnotation {
3       ...
4   }

java.lang.annotation.ElementType是一個枚舉類型,它具有以下定義:

@Retention的用法:指示註釋類型的註釋要保留多久。如果註釋類型聲明中不存在 Retention 註釋,則保留策略默認爲 RetentionPolicy.CLASS,例如:

1 @ Retention(RetentionPolicy.CLASS)
2     public @interface MyAnnotation {
3         ...
4     }

java.lang.annotation.RetentionPolicy是一個枚舉類型,它具有以下定義:

@Documented的用法:指示某一類型的註釋將通過 javadoc 和類似的默認工具進行文檔化。應使用此類型來註釋這些類型的聲明:其註釋會影響由其客戶端註釋的元素的使用。如果類型聲明是用 Documented 來註釋的,則其註釋將成爲註釋元素的公共 API 的一部分。Documented是一個沒有成員的註釋。

@Inherited的用法:指示註釋類型自動被子類繼承。 Inherited也是一個沒有成員的註釋。
注意,如果使用@Inherited註釋類以外的任何事物都是無效的。還要注意,此元註釋僅對從超類繼承註釋有效;對已實現接口的註釋無效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章