我正在尝试对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吗?还是我错过了一个更好的方式?
答案 0 :(得分:77)
简单地将“旧的循环方式”转换为流:
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
return input.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey().substring(subLength),
entry -> AttributeType.GetByName(entry.getValue())));
}
答案 1 :(得分:14)
问题可能有点过时,但您可以简单地使用AbstractMap.SimpleEntry&lt;&gt;如下:
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));
任何其他类似于对象的值对象也会起作用(即ApacheCommons Pair tuple)。
答案 2 :(得分:7)
请制作Collector API的以下部分:
<K, V> Collector<? super Map.Entry<K, V>, ?, Map<K, V>> toMap() {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
}
答案 3 :(得分:4)
在Java 9或更高版本上,可以使用Map.entry
,只要您知道键和值都不为空即可。如果两个值中的任何一个都可以合法为null,则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));
}
答案 4 :(得分:0)
以下是AbacusUtil
的简短解决方案C:\
答案 5 :(得分:0)
作为使用内置 Java 流支持的替代方法,可以使用 StreamEx 库。它通过 EntryStream
类对 Entry
对象流提供流畅的支持:
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();
}