以下是Sotirios Delimanolis的答案的一些变化,从(+1)开始非常好。考虑以下:
static <X, Y, Z> Map<X, Z> transform(Map<? extends X, ? extends Y> input,
Function<Y, Z> function) {
return input.keySet().stream()
.collect(Collectors.toMap(Function.identity(),
key -> function.apply(input.get(key))));
}
这里有几点。首先是在泛型中使用通配符;这使功能更加灵活。例如,如果您希望输出映射具有一个比输入映射的键超类的键,则必须使用通配符:
Map<String, String> input = new HashMap<String, String>();
input.put("string1", "42");
input.put("string2", "41");
Map<CharSequence, Integer> output = transform(input, Integer::parseInt);
(也有一个关于地图值的示例,但它确实是人为设计的,我承认拥有Y的有界通配符仅在边缘情况下有用。)
第二点是entrySet
,我没有在输入映射上运行流,而是在上运行了它keySet
。我认为,这使代码更简洁一些,但其代价是必须从映射中而不是从映射条目中获取值。顺便说一句,我最初key -> key
是第一个参数,toMap()
由于某种原因,此操作因类型推断错误而失败。像把它(X key) -> key
一样更改为有效Function.identity()
。
另一个变化如下:
static <X, Y, Z> Map<X, Z> transform1(Map<? extends X, ? extends Y> input,
Function<Y, Z> function) {
Map<X, Z> result = new HashMap<>();
input.forEach((k, v) -> result.put(k, function.apply(v)));
return result;
}
这使用Map.forEach()
而不是流。我认为这甚至更简单,因为它省去了收集器,而收集器在使用地图时有些笨拙。原因是Map.forEach()
将键和值作为单独的参数给出,而流只有一个值-您必须选择使用键还是映射条目作为该值。在不利的一面,这缺乏其他方法的丰富,流畅的优点。:-)
e -> e.getKey()
为Map.Entry::getKey
。但这只是口味/编程风格的问题。