Effective Java 35 Prefer annotations to naming patterns
Disadvantages of naming patterns
- Typographical errors may result in silent failures.
- There is no way to ensure that they are used only on appropriate program elements.
- They provide no good way to associate parameter values with program elements.
Naming patters example
testXXX
textXXXWithXXXException
Better solution: meta-annotations
// Marker annotation type declaration
import java.lang.annotation.*;
/**
* Indicates that the annotated method is a test method.
* Use only on parameter less static methods.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
/**
* 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 Exception> value();
}
/**
* Annotation type with an array parameter
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MultiExceptionTest {
Class<? extends Exception>[] value();
}
- 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(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.
- The parameter definition Class<? extends Exception> value(); and Class<? extends Exception>[] value(); declare the required one or more exceptions to be generated by the method.
// 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() { }
}
/**
* @author Kaibo
* 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)
}
/**
* @author Kaibo
*
*/
public class Sample3 {
// Code containing an annotation with an array parameter
@MultiExceptionTest({ IndexOutOfBoundsException.class,
NullPointerException.class })
public static void doublyBad() {
List<String> list = new ArrayList<String>();
// The spec permits this method to throw either
// IndexOutOfBoundsException or NullPointerException
list.addAll(5, null);
}
}
/**
* @author Kaibo
* Program to process marker annotations.
*/
import java.lang.reflect.*;
public class RunTests {
public static void main(String[] args) throws Exception {
Class<?> testClass = Class.forName(args[0]);
testSample1(testClass);
testClass = Class.forName(args[1]);
testSample2(testClass);
testClass = Class.forName(args[2]);
testSample3(testClass);
}
private static void testSample1(Class<?> testClass) {
int tests = 0;
int passed = 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);
}
/**
* @param testClass
*/
private static void testSample2(Class<?> testClass) {
int tests = 0;
int passed = 0;
for (Method m : testClass.getDeclaredMethods()) {
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 Exception> 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);
}
}
}
System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);
}
private static void testSample3(Class<?> testClass) {
int tests = 0;
int passed = 0;
for (Method m : testClass.getDeclaredMethods()) {
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();
Class<? extends Exception>[] excTypes = m.getAnnotation(
MultiExceptionTest.class).value();
int oldPassed = passed;
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);
}
}
}
System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);
}
}
Summary
There is simply no reason to use naming patterns now that we have annotations. All programmers should, however, use the predefined annotation types provided by the Java platform(Item 36 and Item24).
Effective Java 35 Prefer annotations to naming patterns的更多相关文章
- Effective Java 69 Prefer concurrency utilities to wait and notify
Principle Use the higher-level concurrency utilities instead of wait and notify for easiness. Use Co ...
- Effective Java 53 Prefer interfaces to reflection
Disadvantage of reflection You lose all the benefits of compile-time type checking, including except ...
- Effective Java 68 Prefer executors and tasks to threads
Principle The general mechanism for executing tasks is the executor service. If you think in terms o ...
- Effective Java 18 Prefer interfaces to abstract classes
Feature Interface Abstract class Defining a type that permits multiple implementations Y Y Permitted ...
- Effective Java 20 Prefer class hierarchies to tagged classes
Disadvantage of tagged classes 1. Verbose (each instance has unnecessary irrelevant fields). 2. Erro ...
- Effective Java 25 Prefer lists to arrays
Difference Arrays Lists 1 Covariant Invariant 2 Reified at runtime Erased at run time 3 Runtime type ...
- Effective Java 46 Prefer for-each loops to traditional for loops
Prior to release 1.5, this was the preferred idiom for iterating over a collection: // No longer the ...
- Effective Java 49 Prefer primitive types to boxed primitives
No. Primitives Boxed Primitives 1 Have their own values Have identities distinct from their values 2 ...
- Effective Java Index
Hi guys, I am happy to tell you that I am moving to the open source world. And Java is the 1st langu ...
随机推荐
- TOGAF培训讲义
我作为国内首先进行TOGAF研究和实践的架构师之一,曾在中国软件技术大会和中国软件工程大会做过TOGAF相关的主题演讲,并在多家大中型企业做过企 业架构内训.这个是我在给需要企业架构的企业做内训时的讲 ...
- Sprint第三个冲刺(第二天)
一.Sprint介绍 任务进度: 二.Sprint周期 看板: 燃尽图:
- (一)Protobuf的Java使用
学习使用Protobuf,创建java文件 windows : 步骤一:两个文件:proto.exe, protobuf-Java-2.4.1.jar 步骤二:建立一个工程CreateProtoBu ...
- C#语法糖
首先需要声明的是“语法糖”这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕不已,呵呵. 1. ...
- 【jQuery基础学习】11 jQuery性能简单优化
关于性能优化 合适的选择器 $("#id")会直接调用底层方法,所以这是最快的.如果这样不能直接找到,也可以用find方法继续查找 $("p")标签选择器也是直 ...
- Hadoop Pipes Exception: Illegal text protocol command
Hadoop Pipes Exception: Illegal text protocol command 对于Hadoop pipes 出现这样的错误,基本上编译代码依赖的.so和.a 版本不匹配 ...
- Urlencode and Urldecode 命令行
由于经常使用,简单记录之 $ alias urlencode='python -c "import sys, urllib as ul; print ul.quote_plus(sys.ar ...
- DoTween小结
using UnityEngine; using System.Collections; using DG.Tweening; public class GetStart : MonoBehaviou ...
- 利用php实现:当获取的网址不是特定网址时候跳转到指定地址
这个问题是在百度知道看到的问答,我不懂做,特定去百度了下.然后结合别人获取域名和跳转的知识,综合做了这个功能,以下是实现代码: <?php //获取当前的域名: echo "获取到的域 ...
- 线上mysql内存持续增长直至内存溢出被killed分析(已解决)
来新公司前,领导就说了,线上生产环境Mysql库经常会发生日间内存爆掉被killed的情况,结果来到这第一天,第一件事就是要根据线上服务器配置优化配置,同时必须找出现在mysql内存持续增加爆掉的原因 ...