Java 8 如何基于流分组对集合执行两个不同的函数?
我正在尝试使用流重构一些不那么优雅的代码。我有一个包含字符串和MyObject的HashMap,当前使用for循环对其进行迭代,如下所示:Java 8 如何基于流分组对集合执行两个不同的函数?,java-8,java-stream,Java 8,Java Stream,我正在尝试使用流重构一些不那么优雅的代码。我有一个包含字符串和MyObject的HashMap,当前使用for循环对其进行迭代,如下所示: Map<String, MyObject> map = new HashMap<>(); Map<String, MyObject> objectsToAdd = new HashMap<>(); for(MyObject object : map.values()){ String idT
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);
此链接有助于使用流收集器减少流量:
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);
这段代码至少有两个问题:1)collect是一个将关闭流的函数,但我们还没有完成;2)我们仍然需要原始对象,但它现在已被缩减为一个connectedtoid映射
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);
Q1)是否存在允许我们根据id的第一个字符对对象进行分组的中间操作
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);
问题2)我们如何做到这一点而不将集合减少到仅包含ID
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);
问题3)最后,一旦集合被分组(将有两个),我们如何像在原始代码中那样对每个组执行单独的函数
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);
最终解决方案(感谢@Holger&@flwn的帮助)
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);
Map methodMapping=newhashmap();
methodMapping.put('i',service1::method1);
methodMapping.put('d',service2::method2);
映射到add=Map.values().stream().Map(MyObject::getConnectedToId)
.filter(StringUtils::isNotEmpty)
.map(id->methodMapping.getOrDefault(id.charAt(0),i->null).apply(id))
.filter(对象::非空)
.collect(Collectors.toMap(MyObject::getId,Function.identity(),(mo1,mo2)->mo2));
普塔尔地图(toAdd);
为了避免并发修改异常,有必要在执行流操作时首先将对象存储在临时映射中,然后在完成后将其添加到最终映射中 您的
流
方法和您的常用方法在返回类型方面非常不同。因此,我将您以前的方法转换为流
API
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);
要减少一些代码,您应该首先构建一个映射
,在映射步骤中进行简明查找。看起来像这样:
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);
Map<Character, Function<String, MyObject>> serviceMapping = new HashMap<>();
serviceMapping.put('i', service1);
serviceMapping.put('d', service2);
还可以使用
forEach
操作将计算值直接添加到map
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);
map.values().stream().map(MyObject::getConnectedToId)
.filter(StringUtils::isEmpty)
.map(id -> serviceMapping.getOrDefault(id.charAt(0), i -> null).apply(id))
.filter(Objects::nonNull)
.forEach(mo -> map.put(mo.getId(), mo));
我假设映射的键是
MyObject
的id
?例如,map.get(object.getId()).equals(object)==true
Yes,HashMap中的键是MyObject的id。为了清楚起见,我对这个问题做了一个小的编辑-idToAdd是myObject上的connectedToId,而不是对象的id。mo1和mo2是否假定为method1和method2?此外,在上一次收集操作中,我得到了“非静态方法无法从静态上下文引用”@Kristina如果已有值发生冲突,则默认的collector::toMap
将抛出异常。因此,您必须提供一个合并函数,该函数负责决定采用哪个元素,即新值还是旧值((mo1,mo2)->mo2
)。@Holger在map
操作开始之前,一切都在进行中。我不得不对serviceMapping
进行一次修改,因为它需要返回MyObject
的函数<代码>映射方法映射=新建HashMap();methodMapping.put('i',service1::getMOById);methodMapping.put('d',service2::getMOById)代码>这看起来对吗?在这种情况下,似乎没有调用这些方法,相反,map
操作返回noresults@Kristina:您没有告诉我们有关service1
和service2
的任何信息。如果它们实现相同的接口或具有定义getMOById
方法的公共基类,则可以简化解决方案。@Holger:不幸的是,它们没有实现相同的接口或具有公共基类。每个服务返回两个不同的DTO对象,然后在返回之前用MyObject
包装它们。