想象一下,我有以下工作lambda表达式:
Map<Field, String> fields = Arrays.stream(resultClass.getDeclaredFields())
.filter(f -> f.isAnnotationPresent(Column.class))
.collect(toMap(f -> {
f.setAccessible(true);
return f;
}, f -> f.getAnnotation(Column.class).name()));
我想在过滤器语句之前创建一个包含 2 个值的流。所以我想做一个映射,但仍然保留原始值。我想实现这样的事情:
this.fields = Arrays.stream(resultClass.getDeclaredFields())
//map to <Field, Annotation> stream
.filter((f, a) -> a != null)
.collect(toMap(f -> {
f.setAccessible(true);
return f;
}, f -> a.name()));
Java 8 流可以做到这一点吗?我已经看过 collect(groupingBy()),但仍然没有成功。
你需要一个包含两个值的Pair
之类的东西。 您可以编写自己的代码,但这里有一些重新利用AbstractMap.SimpleEntry
的代码:
Map<Field, String> fields = Arrays.stream(resultClass.getDeclaredFields())
.map(f -> new AbstractMap.SimpleEntry<>(f, f.getAnnotation(Column.class)))
.filter(entry -> entry.getValue() != null)
.peek(entry -> entry.getKey().setAccessible(true))
.collect(toMap(Map.Entry::getKey, entry -> entry.getValue().name()));
您可以在collect
操作期间一次性完成整个操作,而无需配对类型:
Map<Field, String> fields = Arrays.stream(resultClass.getDeclaredFields())
.collect(HashMap::new, (m,f) -> {
Column c=f.getAnnotation(Column.class);
if(c!=null) {
f.setAccessible(true);
m.put(f, c.name());
}
}, Map::putAll);
不过,对我来说,将两个不合并在一起的操作分开看起来更干净:
Map<Field, String> fields = Arrays.stream(resultClass.getDeclaredFields())
.collect(HashMap::new, (m,f) -> {
Column c=f.getAnnotation(Column.class);
if(c!=null) m.put(f,c.name());
}, Map::putAll);
AccessibleObject.setAccessible(
fields.keySet().stream().toArray(AccessibleObject[]::new), true);
此解决方案确实对具有注释的字段进行两次迭代,但由于它只执行一次安全检查,而不是每个字段执行一次检查,因此它的性能仍可能优于所有其他解决方案。
通常,除非确实存在性能问题,否则您不应该尝试优化,如果您这样做,您应该衡量,而不是猜测操作成本。结果可能令人惊讶,对数据集进行多次迭代并不一定是坏事。
@Peter Lawrey:我用中间地图尝试了你的建议。它现在可以工作,但它不是很漂亮。
this.fields = Arrays.stream(resultClass.getDeclaredFields())
.collect(HashMap<Field, Column>::new, (map, f) -> map.put(f, f.getAnnotation(Column.class)), HashMap::putAll)
.entrySet().stream()
.filter(entry -> entry.getValue() != null)
.peek(entry -> entry.getKey().setAccessible(true))
.collect(toMap(Map.Entry::getKey, entry -> entry.getValue().name()));