我正在尝试对
Map
对象中的每个条目执行映射操作。
我需要去掉键的前缀并将值从一种类型转换为另一种类型。我的代码从
Map<String, String>
获取配置条目并转换为 Map<String, AttributeType>
(AttributeType
只是一个包含一些信息的类。进一步的解释与这个问题无关。)
我使用 Java 8 Streams 所能想到的最好的结果如下:
private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream().flatMap((Map.Entry<String, Object> e) -> {
HashMap<String, AttributeType> r = new HashMap<>();
r.put(e.getKey().substring(subLength), AttributeType.GetByName(e.getValue()));
return r.entrySet().stream();
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
由于
Map.Entry
是一个接口而无法构造它,会导致创建单个条目Map
实例并使用flatMap()
,这看起来很难看。
有更好的选择吗?使用 for 循环似乎更好:
private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
Map<String, AttributeType> result = new HashMap<>();
int subLength = prefix.length();
for(Map.Entry<String, String> entry : input.entrySet()) {
result.put(entry.getKey().substring(subLength), AttributeType.GetByName( entry.getValue()));
}
return result;
}
我应该避免使用 Stream API 吗?还是我错过了更好的方法?
简单地将“旧的 for 循环方式”翻译成流:
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey().substring(subLength),
entry -> AttributeType.GetByName(entry.getValue())));
}
请制作 Collectors API 的以下部分:
<K, V> Collector<? super Map.Entry<K, V>, ?, Map<K, V>> toMap() {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
}
您可以简单地使用
AbstractMap.SimpleEntry<>
,如下所示:
private Map<String, AttributeType> mapConfig(
Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet()
.stream()
.map(e -> new AbstractMap.SimpleEntry<>(
e.getKey().substring(subLength),
AttributeType.GetByName(e.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
任何其他类似
Pair
的值对象也可以工作(例如 Apache Commons Pair
元组)。
Map.entry
,只要你知道键和值都不会为空。 如果任一值可以合法为空,则 AbstractMap.SimpleEntry
(如另一个答案中所建议)或 AbstractMap.SimpleImmutableEntry
是不错的选择。
private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream().map(e ->
Map.entry(e.getKey().substring(subLength), AttributeType.GetByName(e.getValue()))
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
话虽这么说,在这种特殊情况下,临时
Entry
对象中没有真正的值,并且在 Collectors.toMap
内执行键/值映射会更惯用(如 this other answer 中所示)。 然而,创建临时条目对象是有正当理由的,所以了解一下仍然很有帮助。
作为使用内置 Java 流支持的替代方案,可以使用 StreamEx 库。 它通过
Entry
类对
EntryStream
对象流提供流畅支持:
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return EntryStream.of(input)
.mapKeys(key -> key.substring(subLength))
.mapValues(AttributeType::GetByName)
.toMap();
}
Stream.of(input).toMap(e -> e.getKey().substring(subLength),
e -> AttributeType.GetByName(e.getValue()));