如何使用streams在Java8中迭代ArrayList的HashMap

如何使用streams在Java8中迭代ArrayList的HashMap,java,java-8,java-stream,Java,Java 8,Java Stream,我有以下数据集,其中Key为String,value为值列表 我想用key和list的每个值作为方法的参数来调用一个方法。迭代所有键。我可以使用两个forEach循环来完成它,如下面的示例所示。 我想知道我们是否可以在Java8中使用streams和flatMap编写相同的逻辑,而无需forEach内部循环?谢谢 Map<String,ArrayList<String>> xhashMap ; if(xhashMap!=null) { xhashMap.forEa

我有以下数据集,其中Key为String,value为值列表

我想用key和list的每个值作为方法的参数来调用一个方法。迭代所有键。我可以使用两个forEach循环来完成它,如下面的示例所示。 我想知道我们是否可以在Java8中使用streams和flatMap编写相同的逻辑,而无需forEach内部循环?谢谢

Map<String,ArrayList<String>> xhashMap ;

if(xhashMap!=null)  {

 xhashMap.forEach((k,l)-> {

    if(k.equals("ax")){
           l.forEach(v->{
            method1(v,AA.class);
           }
     }
    if(k.equals("bx")){
           l.forEach(v->{
            method1(v,BB.class);
           }
     }

  });

}
Map-xhashMap;
if(xhashMap!=null){
xhashMap.forEach((k,l)->{
如果(k等于(“ax”)){
l、 forEach(v->{
方法1(v,AA级);
}
}
如果(k等于(“bx”)){
l、 forEach(v->{
方法1(v,BB级);
}
}
});
}

是的,我们不能用流API编写它,但也没有太好

由于您正在执行副作用而不收集结果,
Stream
基本上是:

xhashMap.entrySet()
  .stream()
  .forEach(e -> ...);
不幸的是,在
forEach
中包含相同的逻辑

实际上,此时您甚至可以跳过
创建,因为您可以在不创建
流的情况下执行
forEach

xhashMap.entrySet()
  .forEach(e -> ...);

无论您是使用
for
循环、
forEach
还是
API,这都无关紧要。在所有情况下,您都在迭代
映射
以将每个键与某个值进行比较,这会扭曲映射的概念,从而将键与值关联并提供(通常比线性更好)查找方法

此外,您应该使用
映射
,而不是引用像
ArrayList
这样的实现类型,并且首先不要让它为
null
,而不是让它稍后检查
null

如果您遵循这些建议,您的代码将变为

Map<String, List<String>> xhashMap;
// always initialize the map to a non-null reference

xhashMap.getOrDefault("ax", Collections.emptyList())
        .forEach(v -> method1(v, AA.class));
xhashMap.getOrDefault("bx", Collections.emptyList())
        .forEach(v -> method1(v, BB.class));
Map-xhashMap;
//始终将映射初始化为非空引用
xhashMap.getOrDefault(“ax”,Collections.emptyList())
.forEach(v->method1(v,AA.class));
xhashMap.getOrDefault(“bx”,Collections.emptyList())
.forEach(v->method1(v,BB.class));
如变量名所示,如果映射是哈希映射,则两次查找将具有
O(1)
时间复杂度,但即使是
TreeMap
具有
O(log(n))
复杂度也比在映射上迭代并比较所有键要好


只要操作包含一个具有不同参数的唯一方法调用,重复使用公共代码就没有多大好处,因为共享代码要复杂得多。

确保可以使用flatMap和闭包来完成

xHashMap.entrySet().stream()
                .flatMap(e -> e.getValue().stream()
                        .<Runnable>map(v -> () -> {
                            final String k = e.getKey();
                            if (k.equals("ax")) {
                                method1(v, AA.class);
                            }
                            if (k.equals("bx")) {
                                method1(v, BB.class);
                            }
                        })
                )
                .forEach(Runnable::run);
xHashMap.entrySet().stream()
.flatMap(e->e.getValue().stream())
.map(v->()->{
最后一个字符串k=e.getKey();
如果(k等于(“ax”)){
方法1(v,AA级);
}
如果(k等于(“bx”)){
方法1(v,BB级);
}
})
)
.forEach(Runnable::run);

为什么要使用流?流实现似乎更容易混淆;尤其是当您映射到不同的类类型时。我认为如果我们有大量数据流,在这种情况下会表现良好。但我不确定。所以只需检查一下。您认为我做得正确,不能在流中完成。我没有使用streams API的经验。刚开始学习鉴于您正在从内存中已存在的映射中播种数据,使用流可能不会更好-上面的方法可能更好。好的,谢谢您的输入。为什么要在映射上迭代以查找特定键?
Map.getOrDefault(“ax”),emptyList()).forEach(v->method1(v,AA.class))
或者,如果缺少键是一种异常情况,只需
map.get(“ax”).forEach(…)
谢谢@Grzegorz,我同意。我们现在不需要流。您的语句。entryset().forEach(e->…)。我必须再次检查下面基于键的第二个参数。例如,在键“ax”的情况下,它将是AA.class。这就是我必须显式检查键值的原因。@techi e是一个条目,它同时包含键和值-本质上它并不比您的解决方案好