Effective Java之注解优于命名模式(三十五)
Java 1.5之前,一般使用命名模式表明有些程序元素需要通過某種工具或者框架進行特殊處理。例如,JUnit測試框架原本要求用戶一定要用test作為測試方法名稱的開頭。
命名模式的缺點:
- 文字拼寫錯誤導致失敗,測試方法沒有執行,也沒有報錯
- 無法確保它們只用于相應的程序元素上,如希望一個類的所有方法被測試,把類命名為test開頭,但JUnit不支持類級的測試,只在test開頭的方法中生效
- 沒有提供將參數值與程序元素關聯起來的好方法。
注解能解決命名模式存在的問題,下面定義一個注解類型指定簡單的測試,它們自動運行,并在拋出異常時失敗
(注意,下面的Test注解是自定義的,不是JUnit的實現)
@Retention注解有三種
1.RetentionPolicy.SOURCE —— 這種類型的Annotations只在源代碼級別保留,編譯時就會被忽略
2.RetentionPolicy.CLASS —— 這種類型的Annotations編譯時被保留,在class文件中存在,但JVM將會忽略
3.RetentionPolicy.RUNTIME —— 這種類型的Annotations將被JVM保留,所以他們能在運行時被JVM或其他使用反射機制的代碼所讀取和使用.
@Target(ElementType.METHOD)表明只有在方法聲明中Test注解才是合法的
下面的Sample類使用Test注解,如果拼錯Test或者將Test注解應用到除方法外的其他地方,
編譯不會通過
下面是測試運行類:
public class RunTests {public static void main(String[] args) throws ClassNotFoundException {//測試的個數int tests = 0;//測試通過的個數int passed = 0;Class testClass = Class.forName("ex_35.Sample");for(Method m : testClass.getDeclaredMethods()) {//如果方法上存在@Test注解if(m.isAnnotationPresent(Test.class)) {tests++;try {m.invoke(null);passed++;//如果測試方法拋出異常} catch(InvocationTargetException wrappedExc) {Throwable exc = wrappedExc.getCause();System.out.println(m + " failed: " + exc);//如果方法是無效的Test用法,} catch(Exception e) {System.out.println("INVALID @Test: " + m);}}}System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);}}就完成了對@Test注解方法的測試,結果如下:
public static void ex_35.Sample.m3() failed: java.lang.RuntimeException: Boom INVALID @Test: public void ex_35.Sample.m5() public static void ex_35.Sample.m7() failed: java.lang.RuntimeException: Crash Passed: 1, Failed: 3針對只有在拋出異常才成功的注解(有參數注解的方法):
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTest {Class<? extends Exception> value(); }使用:
public class Sample2 {@ExceptionTest(ArithmeticException.class) public static void m1() {int i = 1/0;}測試工具方法也很容易寫,我們知道方法拋出異常時會進入InvocationTargetException,所以在catch那里判斷一下拋出異常的類型就好了。
其他地方與上一個測試類一樣:
catch(InvocationTargetException wrappedExc) {Throwable exc = wrappedExc.getCause();//得到注解上的參數Class<? extends Exception> excType = m.getAnnotation(ExceptionTest.class).value();if(excType instanceof(exc)){pass++;}看懂了測試工作類的寫法,其實離Junit的理解也就很近了,后面我會分析分析Junit的源代碼。
這里主要介紹注解比命名模式的優點,但是實際上我們寫JavaEE用的命名模式很少,幾乎都讓Spring注解給替代了。如果看到必須要特殊進行命名的類或者方法,甚至是文件,我們都要留個心眼。
總結
以上是生活随笔為你收集整理的Effective Java之注解优于命名模式(三十五)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Effective Java之用接口模拟
- 下一篇: Effective Java之坚持使用O