将 "stream in stream" 中的元素映射到 Set
Map elements from "stream in stream" to Set
我是 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());
2 个问题:
- 由于收集了 2 次,我得到的是 Set
而不是 Set。
- 如果注释不存在但调用了 SomeAnnotationClass.class.value(),我会得到一个空指针
我可以用流优雅地实现这个吗?
如@Andy Turner 所述,您可以使用 flatMap
将多个流映射到单个流并避免 NPE
在访问 value()
[=14= 之前检查注释]
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;
}
}
}
一组要展平:
// 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]
我是 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());
2 个问题:
- 由于收集了 2 次,我得到的是 Set
而不是 Set。 - 如果注释不存在但调用了 SomeAnnotationClass.class.value(),我会得到一个空指针
我可以用流优雅地实现这个吗?
如@Andy Turner 所述,您可以使用 flatMap
将多个流映射到单个流并避免 NPE
在访问 value()
[=14= 之前检查注释]
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;
}
}
}
一组要展平:
// 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]