【发布时间】:2016-07-12 17:24:23
【问题描述】:
我正在尝试使用流重构一些不太优雅的代码。我有一个包含字符串和 MyObjects 的 HashMap,目前使用 for 循环对其进行迭代,如下所示:
Map<String, MyObject> map = new HashMap<>();
Map<String, MyObject> objectsToAdd = new HashMap<>();
for(MyObject object : map.values()){
String idToAdd = object.getConnectedToId();
if(StringUtils.isEmpty(idToAdd) {
continue;
}
if(idToAdd.substring(0,1).equals("i")){ // connected to an ICS
MyObject newObject = service1.someMethod(idToAdd);
if(newObject != null) {
objectsToAdd.put(newObject.getId(), newObject);
}
} else if (idToAdd.substring(0,1).equals("d")){ // connected to a device
MyObject newObject = service2.someMethod(idToAdd);
if(newObject != null) {
objectsToAdd.put(newObject.getId(), newObject);
}
}
}
map.putAll(objectsToAdd);
由于我只关心 id,所以我首先使用 map 操作只获取 id,然后使用过滤器操作来消除空的。
下一部分是我遇到的麻烦。我尝试的第一件事是使用 Collectors groupingBy 操作,以便我可以根据 id 的第一个字符对项目进行分组,我最终得到了:
map.values().stream()
.map(myObject -> myObject.getConnectedToId()) // get a map of all the ids
.filter(StringUtils::isNotEmpty) // filter non empty ones
.collect(
Collectors.mapping(
MyObject::getId,
Collectors.toList())),
Collectors.groupingBy(
s -> s.substring(0,1));
此链接有助于减少使用流收集器:Stream Reduction
这段代码至少有两个问题:1)collect 是一个terminal operation,它将关闭流,我们还没有完成;2)我们仍然需要原始对象,但现在它已被简化为connectedToIds 的地图。
Q1) 是否有中间操作允许我们根据 id 的第一个字符对对象进行分组?
Q2)我们如何在不将集合减少到仅 ID 的情况下做到这一点?
Q3) 最后,一旦集合被分组(会有两个),我们如何像原始代码一样在每个组上执行单独的功能?
最终解决方案(感谢@Holger 和@Flown 的帮助)
Map<Character, Function<String, MyObejct>> methodMapping = new HashMap<>();
methodMapping.put('i', service1::method1);
methodMapping.put('d', service2::method2);
Map<String, MyObject> toAdd = map.values().stream().map(MyObject::getConnectedToId)
.filter(StringUtils::isNotEmpty)
.map(id -> methodMapping.getOrDefault(id.charAt(0), i -> null).apply(id))
.filter(Objects::nonNull)
.collect(Collectors.toMap(MyObject::getId, Function.identity(), (mo1, mo2) -> mo2));
map.putAll(toAdd);
为避免并发修改异常,有必要在执行流操作时首先将对象存储在临时映射中,然后在完成后将它们添加到最终映射中。
【问题讨论】:
-
我假设map的key是
MyObject的id? IE。map.get(object.getId()).equals(object) == true -
是的,HashMap中的key就是MyObject的id。为了清楚起见,我对问题进行了小幅编辑 - idToAdd 是 myObject 上的 connectedToId,而不是对象的 id。
标签: java-8 java-stream