如何组合来自 Collectors.groupingBy 的结果

Cri*_*ano 4 java java-stream

我正在玩 Java 反射并学习更多关于 Stream.collect 的信息。

我有一个注释 MyTag,它有两个属性(idtypeenum[Normal|Failure])。此外,我有一个带有 MyTag 的带注释的方法列表,我能够使用 Collectors.groupingBy 通过 MyTag 注释的 id 属性对这些方法进行分组:

List<Method> ml = getMethodsAnnotatedWith(anClass.getClass(),
                                           MyTag.class);
Map<String, List<Method>> map = ml.stream().collect(groupingBy(m -> {
      var ann = m.getDeclaredAnnotation(MyTag.class);
      return ann.anId();
    }, TreeMap::new, toList()));

Run Code Online (Sandbox Code Playgroud)

现在我需要将结果列表减少到一个对象,它只由两个相同 MyTag.id 的项目组成,一个带有 MyTag.type=Normal,另一个带有 MyTag.type=Failure。所以它会产生类似于 Map<String, Pair<Method, Method>> 的结果。如果出现两次以上,我必须只选择第一个,记录并忽略其余的。

我怎么能做到这一点?

Hol*_*ger 6

您可以使用

Map<String, Map<Type, Method>> map = Arrays.stream(anClass.getClass().getMethods())
    .filter(m -> m.isAnnotationPresent(MyTag.class))
    .collect(groupingBy(m -> m.getDeclaredAnnotation(MyTag.class).anId(),
            TreeMap::new,
            toMap(m -> m.getDeclaredAnnotation(MyTag.class).aType(),
                  m -> m, (first, last) -> first,
                  () -> new EnumMap<>(Type.class))));
Run Code Online (Sandbox Code Playgroud)

结果将注释 ID 属性映射到MapType(枚举常量NORMALFAILURE)到具有匹配注释的第一个遇到的方法。虽然“first”在迭代反射发现的方法时没有实际意义,因为它不保证任何特定的顺序。

() -> new EnumMap<>(Type.class)地图工厂是没有必要的,它也将与默认情况下使用时,你不指定厂家通用地图工作。但是EnumMap将以稍微更有效的方式处理只有两个常量要映射的情况,并且它的迭代顺序将匹配枚举常量的声明顺序。

我认为,这EnumMapPair<Method, Method>需要记住哪种方法与“正常”相关,哪种与“失败”相关联要好。适应两个以上的常量也更容易。此外,它EnumMap是内置的,不需要第 3 方库。