3 回答
TA贡献1807条经验 获得超9个赞
这是一个按静态值对字段进行分组的流。请注意有关其他更改/更正的一些评论
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())));
调用读取值的方法如下(主要是为了避免流中的 try/catch 块):
private static Short getValue(Field f) {
try {
return f.getShort(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
TA贡献1817条经验 获得超14个赞
如果您希望有效地进行此检查(通常不那么关心单元测试),您可以通过乐观地假设字段没有重复并首先执行廉价的预测试来减少工作。此外,您可以使用此预测试的结果来获取不带Map.
作为先决条件,我们应该封装反射操作
private static int fieldValue(Field f) {
try {
return f.getShort(null);
}
catch(ReflectiveOperationException ex) {
throw new IllegalStateException();
}
}
此外,我们需要将short值范围的潜在值映射到 a 的正索引BitSet:
private static int shortToIndex(int shortValue) {
return Math.abs(shortValue<<1) | (shortValue>>>31);
}
这假设具有较小量级的数字更常见并保持它们的量级较小,以减小结果BitSet. 如果假定这些值是正的,shortValue & 0xffff那就更可取了。如果两者都不适用,您也可以shortValue - Short.MIN_VALUE改用。
有了映射函数,我们可以使用
@Test
public void testIdsAreUnique() {
BitSet value = new BitSet(), duplicate = new BitSet();
Field[] fields = InterfaceWithIds.class.getDeclaredFields();
Arrays.stream(fields)
.filter(f -> f.getType() == short.class)
.mapToInt(f -> shortToIndex(fieldValue(f)))
.forEach(ix -> (value.get(ix)? duplicate: value).set(ix));
if(duplicate.isEmpty()) return; // no duplicates
throw new AssertionError(Arrays.stream(fields)
.filter(f -> duplicate.get(shortToIndex(fieldValue(f))))
.map(f -> f.getName()+"="+fieldValue(f))
.collect(Collectors.joining(", ", "fields with duplicate values: ", "")));
}
它首先为所有遇到的值填充一个位集,并为多次遇到的值填充另一个位集。如果后一个位集为空,我们可以立即返回,因为没有重复。否则,我们可以使用该位集作为廉价过滤器来获取具有问题值的字段。
添加回答
举报