我是Java流新手。
我有一个包含n个类的数组。
类有几个带有特定注释的字段(SomeAnnotationClass.class)
我试图得到一组所有的字段注释值,这是用这个特定的注释注释。如果字段没有注释,我想要字段的名称。
所以我试着这样做:
Stream.of(clazzes).map( c ->
Stream.of((c.getDeclaredFields()))
.map(
field ->
Optional.ofNullable(
field.getDeclaredAnnotation(SomeAnnotationClass.class).value())
.orElse(field.getName())).collect(Collectors.toSet())).collect(Collectors.toSet());
有两个问题:
- 我得到一个Set
- 如果注释不存在,我得到一个空指针,但SomeAnnotationClass.class.value()被称为
我可以用流优雅地实现这一点吗?
一组集合应该被平行化:
// in Main.java
public static Set<String> getValuesOrNames(Class ... clazzes) {
return Arrays.stream(clazzes) // convert array to Stream<Class>
.flatMap(c -> Arrays.stream(c.getDeclaredFields())) // convert array of fields Stream<Field>
.map(field -> Optional.ofNullable(field.getAnnotation(SomeAnnotationClass.class))
.map(SomeAnnotationClass::value) // assuming SomeAnnotationClass has value method
.orElse(field.getName())
)
.collect(Collectors.toSet());
}
测试// annotation class
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeAnnotationClass {
String value() default "";
}
import java.util.*;
import java.util.stream.Collectors;
import lombok.Data;
public class Main {
public static void main(String[] args) {
System.out.println(getValuesOrNames(Something.class, Main.class));
}
@Data
public static class Something {
@SomeAnnotationClass(value = "String foo")
private String foo;
@SomeAnnotationClass
private String emptyFoo;
private String bar;
@SomeAnnotationClass(value = "int id")
private int id;
}
}
输出[, String foo, bar, int id]
正如@Andy Turner所提到的,您可以使用toflatMap
将多个流映射到单个流,并避免在访问value()
之前检查NPE
的注释
Set<String> value = clazzes.stream().map(c -> Stream.of((c.getDeclaredFields()))
.map(field -> Optional.ofNullable(
field.getDeclaredAnnotation(SomeAnnotationClass.class)).map(SomeAnnotationClass::value).orElseGet(field::getName)).collect(Collectors.toSet()))
.flatMap(Collection::stream).collect(Collectors.toSet());
package io.falcon.instagram.indexer.util;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.Enumerated;
import javax.persistence.Id;
public class Example {
public static void main(String[] args) {
List<Class<?>> classes = List.of(Test.class);
Class<Enumerated> someAnnotationClass = Enumerated.class;
Set<String> fieldNames =
classes.stream()
.flatMap(c -> Arrays.stream(c.getDeclaredFields().clone())) // because getDeclaredFields returns array type
.map((Field field) -> Optional.ofNullable(field.getDeclaredAnnotation(someAnnotationClass)).map(a -> field.getName()))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toSet());
System.out.println(fieldNames);
}
public static class Test {
@Id
private final String id;
@Id
@Enumerated
private final String field;
@Enumerated
private final String another;
@Enumerated
private final String theGame;
public Test(String id, String field, String another, String theGame) {
this.id = id;
this.field = field;
this.another = another;
this.theGame = theGame;
}
}
}