下面是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上运行流。我认为这使得代码更简洁,代价是必须从map条目中获取值,而不是从map条目中获取值。顺便说一句,我最初有key -> key作为toMap()的第一个参数,由于某种原因,这失败了,导致类型推断错误。将其更改为(X键)->键,就像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()将键和值作为单独的参数提供,而流只有一个值——您必须选择是使用键还是使用映射条目作为该值。缺点是,这种方法缺乏其他方法丰富、流畅的优点。: -)