В Java 8 представлены Лямбда-выражения и Типовые аннотации.
С аннотациями типов можно определить аннотации 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 также можно заменить анонимный класс в этом примере выражением лямбда:
public static void main(String[] args) {
List<String> list = Arrays.asList("World!", "Type Annotations!");
testTypeAnnotation(list, p -> System.out.println(p));
}
Но так как компилятор передает аргумент типа Consumer для выражения лямбда, он больше не может комментировать созданный экземпляр пользователя:
testTypeAnnotation(list, @MyTypeAnnotation("Hello ") (p -> System.out.println(p))); // Illegal!
Можно было бы выразить лямбда-выражение в Потребителе, а затем аннотировать ссылку на тип выраженного выражения:
testTypeAnnotation(list,(@MyTypeAnnotation("Hello ") Consumer<String>) (p -> System.out.println(p))); // Legal!
Но это не даст желаемого результата, потому что созданный класс Consumer не будет аннотирован аннотацией выраженного выражения. Выход:
World!
Type Annotations!
Два вопроса:
-
Есть ли способ аннотировать lambda-выражение, похожее на аннотирование соответствующего анонимного класса, поэтому вы получаете ожидаемый вывод "Hello World" в приведенном выше примере?
-
В примере, где я произнес выражение лямбда и аннотировал литой тип: есть ли способ получить этот экземпляр аннотации во время выполнения или такая аннотация всегда неявно ограничивается RetentionPolicy.SOURCE?
Примеры были протестированы с помощью 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);
}
});
}
Но аннотирование параметра не работает для лямбда-выражений:
public static void main(String[] args) {
List<String> list = Arrays.asList("World!", "Type Annotations!");
testTypeAnnotation(list, (@MyTypeAnnotation("Hello ") String str) -> System.out.println(str));
}
Интересно, что также невозможно получить имя параметра (при компиляции с помощью javac -параметра) при использовании лямбда-выражения. Я не уверен, хотя, если это поведение предназначено, если аннотации параметров lambdas еще не реализованы или если это следует считать ошибкой компилятора.