<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## Chapter 6. Enums and Annotations(枚舉和注解) ### Item 39: Prefer annotations to naming patterns(注解優于命名模式) Historically, it was common to use naming patterns to indicate that some program elements demanded special treatment by a tool or framework. For example, prior to release 4, the JUnit testing framework required its users to designate test methods by beginning their names with the characters test [Beck04]. This technique works, but it has several big disadvantages. First, typographical errors result in silent failures. For example, suppose you accidentally named a test method tsetSafetyOverride instead of testSafetyOverride. JUnit 3 wouldn’t complain, but it wouldn’t execute the test either, leading to a false sense of security. 從歷史上看,使用命名模式來標明某些程序元素需要工具或框架特殊處理的方式是很常見的。例如,在版本 4 之前,JUnit 測試框架要求其用戶通過以字符 test [Beck04] 開頭的名稱來指定測試方法。這種技術是有效的,但是它有幾個很大的缺點。首先,排版錯誤會導致沒有提示的失敗。例如,假設你意外地將一個測試方法命名為 tsetSafetyOverride,而不是 testSafetyOverride。JUnit 3 不會報錯,但它也不會執行測試,這導致一種正確執行了測試的假象。 A second disadvantage of naming patterns is that there is no way to ensure that they are used only on appropriate program elements. For example, suppose you called a class TestSafetyMechanisms in hopes that JUnit 3 would automatically test all of its methods, regardless of their names. Again, JUnit 3 wouldn’t complain, but it wouldn’t execute the tests either. 命名模式的第二個缺點是,無法確保只在相應的程序元素上使用它們。例如,假設你調用了一個類 TestSafetyMechanisms,希望 JUnit 3 能夠自動測試它的所有方法,而不管它們的名稱是什么。同樣,JUnit 3 不會報錯,但它也不會執行測試。 A third disadvantage of naming patterns is that they provide no good way to associate parameter values with program elements. For example, suppose you want to support a category of test that succeeds only if it throws a particular exception. The exception type is essentially a parameter of the test. You could encode the exception type name into the test method name using some elaborate naming pattern, but this would be ugly and fragile (Item 62). The compiler would have no way of knowing to check that the string that was supposed to name an exception actually did. If the named class didn’t exist or wasn’t an exception, you wouldn’t find out until you tried to run the test. 命名模式的第三個缺點是,它們沒有提供將參數值與程序元素關聯的好方法。例如,假設你希望支持只有在拋出特定異常時才成功的測試類別。異常類型本質上是測試的一個參數。你可以使用一些精心設計的命名模式,將異常類型名稱編碼到測試方法名稱中,但這樣的代碼將不好看且脆弱([Item-62](/Chapter-9/Chapter-9-Item-62-Avoid-strings-where-other-types-are-more-appropriate.md))。編譯器將無法檢查這些用于命名異常的字符串是否確實執行了。如果指定的類不存在或不是異常,則在運行測試之前不會被發現。 Annotations [JLS, 9.7] solve all of these problems nicely, and JUnit adopted them starting with release 4. In this item, we’ll write our own toy testing framework to show how annotations work. Suppose you want to define an annotation type to designate simple tests that are run automatically and fail if they throw an exception. Here’s how such an annotation type, named Test, might look: 注解 [JLS, 9.7] 很好地解決了所有這些問題,JUnit 從版本 4 開始就采用了它們。在本條目中,我們將編寫自己的示例測試框架來展示注解是如何工作的。假設你希望定義注解類型,以指定自動運行的簡單測試,并在拋出異常時失敗。下面是這種名為 Test 的注解類型的概貌: ``` // Marker annotation type declaration import java.lang.annotation.*; /** * Indicates that the annotated method is a test method. * Use only on parameterless static methods. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Test { } ``` The declaration for the Test annotation type is itself annotated with Retention and Target annotations. Such annotations on annotation type declarations are known as meta-annotations. The @Retention(RetentionPolicy.RUNTIME) meta-annotation indicates that Test annotations should be retained at runtime. Without it, Test annotations would be invisible to the test tool. The @Target.get(ElementType.METHOD) meta-annotation indicates that the Test annotation is legal only on method declarations: it cannot be applied to class declarations, field declarations, or other program elements. Test 注解類型的聲明本身帶有 Retention 注解和 Target 注解。這種注解類型聲明上的注解稱為元注解。`@Retention(RetentionPolicy.RUNTIME)` 元注解表明測試注解應該在運行時保留。沒有它,測試工具將無法識別測試注解。`@Target.get(ElementType.METHOD)` 元注解表明測試注解僅對方法聲明合法:它不能應用于類聲明、字段聲明或其他程序元素。 **譯注 1:注解的保留策略** 保留策略決定了在什么位置丟棄注解。Java 定義了 3 種策略,它們被封裝到 `java.lang.annotation.RetentionPolicy` 枚舉中。這 3 種策略分別是 SOURCE、CLASS 和 RUNTIME。 - 使用 SOURCE 保留策略的注解,只在源文件中保留,在編譯期間會被拋棄。 - 使用 CLASS 保留策略的注解,在編譯時被存儲到 `.class` 文件中。但是,在運行時不能通過 JVM 得到這些注解。 - 使用 RUNTIME 保留策略的注解,在編譯時被存儲到 `.class` 文件中,并且在運行時可以通過 JVM 獲取這些注解。因此,RUNTIME 保留策略提供了最永久的注解。 **譯注 2:ElementType 各常量定義的范圍** - ElementType.TYPE - Class, interface (including annotation type), or enum declaration(類、接口、注解、枚舉) - ElementType.FIELD - Field declaration (includes enum constants)(字段、枚舉常量) - ElementType.METHOD - Method declaration(方法) - ElementType.PARAMETER - Formal parameter declaration(方法參數) - ElementType.CONSTRUCTOR - Constructor declaration(構造) - ElementType.LOCAL_VARIABLE - Local variable declaration(局部變量) - ElementType.ANNOTATION_TYPE - Annotation type declaration(注解) - ElementType.PACKAGE - Package declaration(包) - ElementType.TYPE_PARAMETER - Type parameter declaration(泛型參數) - Since: 1.8 - ElementType.TYPE_USE - Use of a type(任意類型,獲取 class 對象和 import 兩種情況除外) - Since: 1.8 - ElementType.MODULE - Module declaration([模塊](https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-C23AFD78-C777-460B-8ACE-58BE5EA681F6)) - Since: 9 The comment before the Test annotation declaration says, “Use only on parameterless static methods.” It would be nice if the compiler could enforce this, but it can’t, unless you write an annotation processor to do so. For more on this topic, see the documentation for javax.annotation.processing. In the absence of such an annotation processor, if you put a Test annotation on the declaration of an instance method or on a method with one or more parameters, the test program will still compile, leaving it to the testing tool to deal with the problem at runtime. Test 注解聲明之前的代碼注釋是這么描述的:「Use only on parameterless static methods.(只對無參數的靜態方法使用)」如果編譯器能夠強制執行這一點,那就太好了,但是它不能,除非你編寫代碼注釋處理器來執行。有關此主題的更多信息,請參閱 `javax.annotation.processing` 的文檔。在沒有這樣的代碼注釋處理程序的情況下,如果你將 Test 注解放在實例方法的聲明上,或者放在帶有一個或多個參數的方法上,測試程序仍然會編譯,讓測試工具在運行時處理。 Here is how the Test annotation looks in practice. It is called a marker annotation because it has no parameters but simply “marks” the annotated element. If the programmer were to misspell Test or to apply the Test annotation to a program element other than a method declaration, the program wouldn’t compile: 下面是 Test 注解實際使用時的樣子。它被稱為標記注解,因為它沒有參數,只是對帶注解的元素進行「標記」。如果程序員拼錯 Test 或將 Test 注解應用于除方法聲明之外的程序元素,程序將無法編譯: ``` // Program containing marker annotations public class Sample { @Test public static void m1() { } // Test should pass public static void m2() { } @Test public static void m3() { // Test should fail throw new RuntimeException("Boom"); } public static void m4() { } @Test public void m5() { } // INVALID USE: nonstatic method public static void m6() { } @Test public static void m7() { // Test should fail throw new RuntimeException("Crash"); } public static void m8() { } } ``` The Sample class has seven static methods, four of which are annotated as tests. Two of these, m3 and m7, throw exceptions, and two, m1 and m5, do not. But one of the annotated methods that does not throw an exception, m5, is an instance method, so it is not a valid use of the annotation. In sum, Sample contains four tests: one will pass, two will fail, and one is invalid. The four methods that are not annotated with the Test annotation will be ignored by the testing tool. Sample 類有 7 個靜態方法,其中 4 個被注解為 Test。其中兩個方法 m3 和 m7 拋出異常,另外兩個 m1 和 m5 沒有拋出異常。但是,不拋出異常的帶注解的方法 m5 是一個實例方法,因此它不是注解的有效使用。總之,Sample 包含四個測試:一個通過,兩個失敗,一個無效。沒有使用 Test 注釋的四個方法將被測試工具忽略。 The Test annotations have no direct effect on the semantics of the Sample class. They serve only to provide information for use by interested programs. More generally, annotations don’t change the semantics of the annotated code but enable it for special treatment by tools such as this simple test runner: Test 注解對 Sample 類的語義沒有直接影響。它們僅用于向相關程序提供信息。更普遍的是,注解不會改變被注解代碼的語義,而是通過工具(就像如下這個簡單的 RunTests 類)對其進行特殊處理: ``` // Program to process marker annotations import java.lang.reflect.*; public class RunTests { public static void main(String[] args) throws Exception { int tests = 0; int passed = 0; Class<?> testClass = Class.forName(args[0]); for (Method m : testClass.getDeclaredMethods()) { if (m.isAnnotationPresent(Test.class)) { tests++; try { m.invoke(null); passed++; } catch (InvocationTargetException wrappedExc) { Throwable exc = wrappedExc.getCause(); System.out.println(m + " failed: " + exc); } catch (Exception exc) { System.out.println("Invalid @Test: " + m); } } } System.out.printf("Passed: %d, Failed: %d%n",passed, tests - passed); } } ``` The test runner tool takes a fully qualified class name on the command line and runs all of the class’s Test-annotated methods reflectively, by calling Method.invoke. The isAnnotationPresent method tells the tool which methods to run. If a test method throws an exception, the reflection facility wraps it in an InvocationTargetException. The tool catches this exception and prints a failure report containing the original exception thrown by the test method, which is extracted from the InvocationTargetException with the getCause method. test runner 工具以命令行方式接受一個完全限定的類名,并通過調用 `Method.invoke` 以反射方式運行類的所有帶測試注解的方法。isAnnotationPresent 方法告訴工具要運行哪些方法。如果測試方法拋出異常,反射工具將其封裝在 InvocationTargetException 中。該工具捕獲這個異常并打印一個失敗報告,其中包含測試方法拋出的原始異常,該異常是用 getCause 方法從 InvocationTargetException 提取的。 If an attempt to invoke a test method by reflection throws any exception other than InvocationTargetException, it indicates an invalid use of the Test annotation that was not caught at compile time. Such uses include annotation of an instance method, of a method with one or more parameters, or of an inaccessible method. The second catch block in the test runner catches these Test usage errors and prints an appropriate error message. Here is the output that is printed if RunTests is run on Sample: 如果通過反射調用測試方法時拋出除 InvocationTargetException 之外的任何異常,則表明在編譯時存在未捕獲的 Test 注解的無效用法。這些用途包括實例方法的注解、帶有一個或多個參數的方法的注解或不可訪問方法的注解。測試運行程序中的第二個 catch 塊捕獲這些 Test 使用錯誤并打印對應的錯誤消息。如果在 Sample 上運行 RunTests,輸出如下: ``` public static void Sample.m3() failed: RuntimeException: Boom Invalid @Test: public void Sample.m5() public static void Sample.m7() failed: RuntimeException: Crash Passed: 1, Failed: 3 ``` Now let’s add support for tests that succeed only if they throw a particular exception. We’ll need a new annotation type for this: 現在讓我們添加一個只在拋出特定異常時才成功的測試支持。我們需要一個新的注解類型: ``` // Annotation type with a parameter import java.lang.annotation.*; /** * Indicates that the annotated method is a test method that * must throw the designated exception to succeed. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTest { Class<? extends Throwable> value(); } ``` The type of the parameter for this annotation is `Class<? extends Throwable>`. This wildcard type is, admittedly, a mouthful. In English, it means “the Class object for some class that extends Throwable,” and it allows the user of the annotation to specify any exception (or error) type. This usage is an example of a bounded type token (Item 33). Here’s how the annotation looks in practice. Note that class literals are used as the values for the annotation parameter: 這個注解的參數類型是 `Class<? extends Throwable>`,這個通配符類型確實很復雜。在英語中,它的意思是「某個擴展自 Throwable 的類的 Class 對象」,它允許注解的用戶指定任何異常(或錯誤)類型。這種用法是有界類型令牌([Item-33](/Chapter-5/Chapter-5-Item-33-Consider-typesafe-heterogeneous-containers.md))的一個示例。下面是這個注解在實際應用時的樣子。注意,類的字面量被用作注解參數的值: ``` // Program containing annotations with a parameter public class Sample2 { @ExceptionTest(ArithmeticException.class) public static void m1() { // Test should pass int i = 0; i = i / i; } @ExceptionTest(ArithmeticException.class) public static void m2() { // Should fail (wrong exception) int[] a = new int[0]; int i = a[1]; } @ExceptionTest(ArithmeticException.class) public static void m3() { } // Should fail (no exception) } ``` Now let’s modify the test runner tool to process the new annotation. Doing so consists of adding the following code to the main method: 現在讓我們修改 test runner 工具來處理新的注解。向 main 方法添加以下代碼: ``` if (m.isAnnotationPresent(ExceptionTest.class)) { tests++; try { m.invoke(null); System.out.printf("Test %s failed: no exception%n", m); } catch (InvocationTargetException wrappedEx) { Throwable exc = wrappedEx.getCause(); Class<? extends Throwable> excType =m.getAnnotation(ExceptionTest.class).value(); if (excType.isInstance(exc)) { passed++; } else { System.out.printf("Test %s failed: expected %s, got %s%n",m, excType.getName(), exc); } } catch (Exception exc) { System.out.println("Invalid @Test: " + m); } } ``` This code is similar to the code we used to process Test annotations, with one exception: this code extracts the value of the annotation parameter and uses it to check if the exception thrown by the test is of the right type. There are no explicit casts, and hence no danger of a ClassCastException. The fact that the test program compiled guarantees that its annotation parameters represent valid exception types, with one caveat: if the annotation parameters were valid at compile time but the class file representing a specified exception type is no longer present at runtime, the test runner will throw TypeNotPresentException. 這段代碼與我們用來處理 Test 注解的代碼類似,只有一個不同:這段代碼提取注解參數的值,并使用它來檢查測試拋出的異常是否是正確的類型。這里沒有顯式的強制類型轉換,因此沒有 ClassCastException 的危險。編譯的測試程序保證其注解參數表示有效的異常類型,但有一點需要注意:如果注解參數在編譯時有效,但表示指定異常類型的類文件在運行時不再存在,那么測試運行程序將拋出 TypeNotPresentException。 Taking our exception testing example one step further, it is possible to envision a test that passes if it throws any one of several specified exceptions. The annotation mechanism has a facility that makes it easy to support this usage. Suppose we change the parameter type of the ExceptionTest annotation to be an array of Class objects: 進一步修改我們的異常測試示例,如果它拋出幾個指定異常中的任意一個,那么可以認為測試通過了。注解機制具有一種工具,可以輕松地支持這種用法。假設我們將 ExceptionTest 注解的參數類型更改為一個 Class 對象數組: ``` // Annotation type with an array parameter @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTest { Class<? extends Exception>[] value(); } ``` The syntax for array parameters in annotations is flexible. It is optimized for single-element arrays. All of the previous ExceptionTest annotations are still valid with the new array-parameter version of ExceptionTest and result in single-element arrays. To specify a multiple-element array, surround the elements with curly braces and separate them with commas: 注解中數組參數的語法是靈活的。它針對單元素數組進行了優化。前面的 ExceptionTest 注解對于 ExceptionTest 的新數組參數版本仍然有效,并且可以生成單元素數組。要指定一個多元素數組,用花括號包圍元素,并用逗號分隔它們: ``` // Code containing an annotation with an array parameter @ExceptionTest({ IndexOutOfBoundsException.class,NullPointerException.class }) public static void doublyBad() { List<String> list = new ArrayList<>(); // The spec permits this method to throw either // IndexOutOfBoundsException or NullPointerException list.addAll(5, null); } ``` It is reasonably straightforward to modify the test runner tool to process the new version of ExceptionTest. This code replaces the original version: 修改測試運行器工具來處理 ExceptionTest 的新版本是相當簡單的。這段代碼替換了原來的版本: ``` if (m.isAnnotationPresent(ExceptionTest.class)) { tests++; try { m.invoke(null); System.out.printf("Test %s failed: no exception%n", m); } catch (Throwable wrappedExc) { Throwable exc = wrappedExc.getCause(); int oldPassed = passed; Class<? extends Exception>[] excTypes =m.getAnnotation(ExceptionTest.class).value(); for (Class<? extends Exception> excType : excTypes) { if (excType.isInstance(exc)) { passed++; break; } } if (passed == oldPassed) System.out.printf("Test %s failed: %s %n", m, exc); } } ``` As of Java 8, there is another way to do multivalued annotations. Instead of declaring an annotation type with an array parameter, you can annotate the declaration of an annotation with the @Repeatable meta-annotation, to indicate that the annotation may be applied repeatedly to a single element. This meta-annotation takes a single parameter, which is the class object of a containing annotation type, whose sole parameter is an array of the annotation type [JLS, 9.6.3]. Here’s how the annotation declarations look if we take this approach with our ExceptionTest annotation. Note that the containing annotation type must be annotated with an appropriate retention policy and target, or the declarations won’t compile: 在 Java 8 中,還有另一種方法可以執行多值注解。你可以在注解聲明上使用 `@Repeatable` 元注解,以表明注解可以重復地應用于單個元素,而不是使用數組參數來聲明注解類型。這個元注解只接受一個參數,這個參數是包含注解類型的類對象,它的唯一參數是注解類型的數組 [JLS, 9.6.3]。如果我們對 ExceptionTest 注解采用這種方法,那么注解聲明是這樣的。注意,包含的注解類型必須使用適當的 Retention 注解和 Target 注解,否則聲明將無法編譯: ``` // Repeatable annotation type @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Repeatable(ExceptionTestContainer.class) public @interface ExceptionTest { Class<? extends Exception> value(); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTestContainer { ExceptionTest[] value(); } ``` Here’s how our doublyBad test looks with a repeated annotation in place of an array-valued annotation: 下面是使用重復注解代替數組值注解的 doublyBad 測試: ``` // Code containing a repeated annotation @ExceptionTest(IndexOutOfBoundsException.class) @ExceptionTest(NullPointerException.class) public static void doublyBad() { ... } ``` Processing repeatable annotations requires care. A repeated annotation generates a synthetic annotation of the containing annotation type. The getAnnotationsByType method glosses over this fact, and can be used to access both repeated and non-repeated annotations of a repeatable annotation type. But isAnnotationPresent makes it explicit that repeated annotations are not of the annotation type, but of the containing annotation type. If an element has a repeated annotation of some type and you use the isAnnotationPresent method to check if the element has an annotation of that type, you’ll find that it does not. Using this method to check for the presence of an annotation type will therefore cause your program to silently ignore repeated annotations. Similarly, using this method to check for the containing annotation type will cause the program to silently ignore non-repeated annotations. To detect repeated and non-repeated annotations with isAnnotationPresent, you much check for both the annotation type and its containing annotation type. Here’s how the relevant part of our RunTests program looks when modified to use the repeatable version of the ExceptionTest annotation: 處理可重復注解需要小心。「重復狀態」會生成名為「容器注解類型」的合成注解。getAnnotationsByType 方法可忽略這一區別,它可以用于訪問可重復注解類型的「重復狀態」和「非重復狀態」。但是 isAnnotationPresent 明確指出,「重復狀態」的情況不屬于注解類型,而是「容器注解類型」。如果一個元素是某種類型的「重復狀態」注解,并且你使用 isAnnotationPresent 方法檢查該元素是否具有該類型的注解,你將發現它提示不存在。因此,使用此方法檢查注解類型的存在與否,將導致你的程序忽略「重復狀態」。類似地,使用此方法檢查「容器注解類型」將導致程序忽略「非重復狀態」。要使用 isAnnotationPresent 檢測「重復狀態」和「非重復狀態」,需要同時檢查注解類型及其「容器注解類型」。下面是我們的 RunTests 程序的相關部分修改為使用 ExceptionTest 注解的可重復版本時的樣子: ``` // Processing repeatable annotations if (m.isAnnotationPresent(ExceptionTest.class)|| m.isAnnotationPresent(ExceptionTestContainer.class)) { tests++; try { m.invoke(null); System.out.printf("Test %s failed: no exception%n", m); } catch (Throwable wrappedExc) { Throwable exc = wrappedExc.getCause(); int oldPassed = passed; ExceptionTest[] excTests =m.getAnnotationsByType(ExceptionTest.class); for (ExceptionTest excTest : excTests) { if (excTest.value().isInstance(exc)) { passed++; break; } } if (passed == oldPassed) System.out.printf("Test %s failed: %s %n", m, exc); } } ``` **譯注:比較原文中提及的 getAnnotationsByType 與 isAnnotationPresent 在可重復注解的「重復狀態」和「非重復狀態」下的使用差別:** **原 doublyBad 方法不變,屬于「重復狀態」(重復注解大于等于兩個的,都屬于「重復狀態」);新增一個 doublyBad2 方法,僅使用一個重復注解,屬于「非重復狀態」** ``` class Simple4 { // Code containing a repeated annotation @ExceptionTest(IndexOutOfBoundsException.class) @ExceptionTest(NullPointerException.class) public static void doublyBad() { } @ExceptionTest(ArithmeticException.class) public static void doublyBad2() { } } ``` **測試代碼** ``` public static void main(String[] args) throws NoSuchMethodException { Class<?> testClass = Simple4.class; for (int count = 1; count <= 2; count++) { Method m = testClass.getMethod(count == 1 ? "doublyBad" : "doublyBad" + count); System.out.println(m.getName() + "「重復狀態」:" + m.isAnnotationPresent(ExceptionTest.class)); System.out.println(m.getName() + "「容器注解類型」:" + m.isAnnotationPresent(ExceptionTestContainer.class)); System.out.println(m.getName() + "「非重復狀態」:" + m.isAnnotationPresent(ExceptionTest.class)); System.out.println(m.getName() + "「重復狀態」:" + m.getAnnotationsByType(ExceptionTest.class)); System.out.println(m.getName() + "「容器注解類型」:" + m.getAnnotationsByType(ExceptionTestContainer.class)); System.out.println(m.getName() + "「非重復狀態」:" + m.getAnnotationsByType(ExceptionTest.class)); } } ``` **結果** ``` doublyBad「重復狀態」:false doublyBad「容器注解類型」:true doublyBad「非重復狀態」:false doublyBad「重復狀態」:[LItem_39.ExceptionTest;@1593948d doublyBad「容器注解類型」:[LItem_39.ExceptionTestContainer;@1b604f19 doublyBad「非重復狀態」:[LItem_39.ExceptionTest;@7823a2f9 doublyBad2「重復狀態」:true doublyBad2「容器注解類型」:false doublyBad2「非重復狀態」:true doublyBad2「重復狀態」:[LItem_39.ExceptionTest;@cb5822 doublyBad2「容器注解類型」:[LItem_39.ExceptionTestContainer;@4b9e13df doublyBad2「非重復狀態」:[LItem_39.ExceptionTest;@2b98378d ``` Repeatable annotations were added to improve the readability of source code that logically applies multiple instances of the same annotation type to a given program element. If you feel they enhance the readability of your source code, use them, but remember that there is more boilerplate in declaring and processing repeatable annotations, and that processing repeatable annotations is error-prone. 添加可重復注解是為了提高源代碼的可讀性,源代碼在邏輯上將同一注解類型的多個實例應用于給定的程序元素。如果你覺得它們增強了源代碼的可讀性,那么就使用它們,但是請記住,在聲明和處理可重復注解方面有更多的樣板,并且處理可重復注解很容易出錯。 The testing framework in this item is just a toy, but it clearly demonstrates the superiority of annotations over naming patterns, and it only scratches the surface of what you can do with them. If you write a tool that requires programmers to add information to source code, define appropriate annotation types. **There is simply no reason to use naming patterns when you can use annotations instead.** 本條目中的測試框架只是一個示例,但是它清楚地展示了注解相對于命名模式的優勢,并且它只涉及到你可以使用它們做什么。如果你編寫的工具要求程序員向源代碼中添加信息,請定義適當的注解類型。**如果可以使用注解,那么就沒有理由使用命名模式。** That said, with the exception of toolsmiths, most programmers will have no need to define annotation types. But **all programmers should use the predefined annotation types that Java provides** (Items 40, 27). Also, consider using the annotations provided by your IDE or static analysis tools. Such annotations can improve the quality of the diagnostic information provided by these tools. Note, however, that these annotations have yet to be standardized, so you may have some work to do if you switch tools or if a standard emerges. 也就是說,除了 toolsmiths 之外,大多數程序員不需要定義注解類型。但是所有程序員都應該使用 Java 提供的預定義注解類型([Item-40](/Chapter-6/Chapter-6-Item-40-Consistently-use-the-Override-annotation.md) 和 [Item-27](/Chapter-5/Chapter-5-Item-27-Eliminate-unchecked-warnings.md))。另外,考慮使用 IDE 或靜態分析工具提供的注解。這些注解可以提高這些工具提供的診斷信息的質量。但是,請注意,這些注解還沒有標準化,因此,如果你切換了工具或出現了標準,那么你可能需要做一些工作。 --- **[Back to contents of the chapter(返回章節目錄)](/Chapter-6/Chapter-6-Introduction.md)** - **Previous Item(上一條目):[Item 38: Emulate extensible enums with interfaces(使用接口模擬可擴展枚舉)](/Chapter-6/Chapter-6-Item-38-Emulate-extensible-enums-with-interfaces.md)** - **Next Item(下一條目):[Item 40: Consistently use the Override annotation(堅持使用 @Override 注解)](/Chapter-6/Chapter-6-Item-40-Consistently-use-the-Override-annotation.md)**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看