如何从流中计算Map,然后检查地图值的属性?

Gho*_*ica 7 java hashmap java-8 java-stream

我的要求:我的接口只包含诸如的条目public final static short SOME_CONST = whatever.问题:短常数需要是唯一的.并且当存在重复时,我主要感兴趣的是导致冲突的SOME_CONST_A,SOME_CONST_B,...名称.

我写下面的测试来测试通过反射.它有效,但我发现它很笨重而且不是很优雅:

@Test
public void testIdsAreUnique() {
    Map<Short, List<String>> fieldNamesById = new LinkedHashMap<>();
    Arrays.stream(InterfaceWithIds.class.getDeclaredFields())
            .filter(f -> f.getClass().equals(Short.class))
            .forEach((f) -> {
        Short key = null;
        String name = null;
        try {
            key = f.getShort(null);
            name = f.getName();
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        fieldNamesById.computeIfAbsent(key, x -> new ArrayList<>()).add(name);
    });

    assertThat(fieldNamesById.entrySet().stream().filter(e -> e.getValue().size() > 1)
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)), is(Collections.emptyMap()));
}
Run Code Online (Sandbox Code Playgroud)

有没有办法避免中间本地地图实例?

(奖励问题:有没有更好的方法来缩短用键/值对填充地图的lambda?)

ern*_*t_k 4

这是一个按静态值对字段进行分组的流。请注意有关其他更改/更正的一些评论

Map<Short, List<String>> fieldNamesById = 
        Arrays.stream(InterfaceWithIds.class.getDeclaredFields())

         //using short.class, not Short.class
        .filter(f -> f.getType().equals(short.class)) 

        //group by value, mapping fields to their names in a list
        .collect(Collectors.groupingBy(f -> getValue(f),
                Collectors.mapping(Field::getName, Collectors.toList())));
Run Code Online (Sandbox Code Playgroud)

读取值所调用的方法如下(主要是为了避免流中的 try/catch 块):

private static Short getValue(Field f) {
    try {
        return f.getShort(null);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我也检查了修饰符,直到我意识到:它是一个接口,因此所有成员都是隐式公共最终静态的。所以这个检查是多余的;-) (2认同)
  • 类不需要使用 equals,f.getType() == Short.class 就足够了。@Eugene我宁愿使用 `Collectors.groupingBy(..., HashMap::new, ...)` 来确保可变映射,然后使用 `fieldNamesById.values().removeIf(l -&gt; l.size()==1 );` 最后 `if(!fieldNamesById.isEmpty()) throw new AssertionError(fieldNamesById.toString());` (2认同)