首页 > 解决方案 > 将元素从“流中流”映射到 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个问题:

  1. 由于收集了 2 次,我得到了 Set<Set> 而不是 Set。
  2. 如果注释不存在但调用 SomeAnnotationClass.class.value() 我会得到一个 Nullpointer

我可以通过流优雅地实现这一点吗?

标签: javacollectionsjava-stream

解决方案


一组集合应该被展平:

// 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]

推荐阅读