【发布时间】:2014-04-18 00:37:32
【问题描述】:
Java 8 引入了Lambda Expressions 和Type Annotations。
使用类型注解,可以像下面这样定义Java注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface MyTypeAnnotation {
public String value();
}
然后可以在任何类型引用上使用此注释,例如:
Consumer<String> consumer = new @MyTypeAnnotation("Hello ") Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
};
这是一个完整的例子,它使用这个注解来打印“Hello World”:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedType;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class Java8Example {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface MyTypeAnnotation {
public String value();
}
public static void main(String[] args) {
List<String> list = Arrays.asList("World!", "Type Annotations!");
testTypeAnnotation(list, new @MyTypeAnnotation("Hello ") Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
});
}
public static void testTypeAnnotation(List<String> list, Consumer<String> consumer){
MyTypeAnnotation annotation = null;
for (AnnotatedType t : consumer.getClass().getAnnotatedInterfaces()) {
annotation = t.getAnnotation(MyTypeAnnotation.class);
if (annotation != null) {
break;
}
}
for (String str : list) {
if (annotation != null) {
System.out.print(annotation.value());
}
consumer.accept(str);
}
}
}
输出将是:
Hello World!
Hello Type Annotations!
在 Java 8 中,也可以用 lambda 表达式替换此示例中的匿名类:
public static void main(String[] args) {
List<String> list = Arrays.asList("World!", "Type Annotations!");
testTypeAnnotation(list, p -> System.out.println(p));
}
但由于编译器推断 lambda 表达式的 Consumer 类型参数,因此无法再注释创建的 Consumer 实例:
testTypeAnnotation(list, @MyTypeAnnotation("Hello ") (p -> System.out.println(p))); // Illegal!
可以将 lambda 表达式转换为 Consumer,然后注释转换表达式的类型引用:
testTypeAnnotation(list,(@MyTypeAnnotation("Hello ") Consumer<String>) (p -> System.out.println(p))); // Legal!
但这不会产生想要的结果,因为创建的 Consumer 类不会被强制转换表达式的注解所注解。输出:
World!
Type Annotations!
两个问题:
是否有任何方法可以对 lambda 表达式进行注释,类似于注释相应的匿名类,以便在上面的示例中获得预期的“Hello World”输出?
1234563 p>
这些示例已经使用 javac 和 Eclipse 编译器进行了测试。
更新
我尝试了@assylias 的建议,改为注释参数,这产生了一个有趣的结果。这是更新的测试方法:
public static void testTypeAnnotation(List<String> list, Consumer<String> consumer){
MyTypeAnnotation annotation = null;
for (AnnotatedType t : consumer.getClass().getAnnotatedInterfaces()) {
annotation = t.getAnnotation(MyTypeAnnotation.class);
if (annotation != null) {
break;
}
}
if (annotation == null) {
// search for annotated parameter instead
loop: for (Method method : consumer.getClass().getMethods()) {
for (AnnotatedType t : method.getAnnotatedParameterTypes()) {
annotation = t.getAnnotation(MyTypeAnnotation.class);
if (annotation != null) {
break loop;
}
}
}
}
for (String str : list) {
if (annotation != null) {
System.out.print(annotation.value());
}
consumer.accept(str);
}
}
现在,当注释匿名类的参数时,也可以产生“Hello World”结果:
public static void main(String[] args) {
List<String> list = Arrays.asList("World!", "Type Annotations!");
testTypeAnnotation(list, new Consumer<String>() {
@Override
public void accept(@MyTypeAnnotation("Hello ") String str) {
System.out.println(str);
}
});
}
但是对参数进行注释不对 lambda 表达式起作用:
public static void main(String[] args) {
List<String> list = Arrays.asList("World!", "Type Annotations!");
testTypeAnnotation(list, (@MyTypeAnnotation("Hello ") String str) -> System.out.println(str));
}
有趣的是,当使用 lambda 表达式时,也无法接收参数的名称(使用 javac -parameter 编译时)。不过,我不确定,如果这种行为是有意的,是否尚未实现 lambda 的参数注释,或者这是否应该被视为编译器的错误。
【问题讨论】:
-
你也可以试试
(@MyTypeAnnotation("Hello ") String s) -> System.out.println(s)虽然我还没有设法访问注释值... -
@assylias 感谢您的意见 - 好主意。我用带注释的参数做了一些测试,并将结果添加到我的问题的更新部分。
-
@assylias 更新:无法接收 lambda 表达式的形式参数的类型注释,如您的示例所示,很可能与 JDK bug 8027181 和 Eclipse bug 430571 有关。
标签: java lambda annotations java-8