使用streams有条件地填充映射-Java8

使用streams有条件地填充映射-Java8,java,intellij-idea,lambda,java-8,java-stream,Java,Intellij Idea,Lambda,Java 8,Java Stream,我正在尝试将此(简化)代码转换为使用Java-8流: Map<String, String> files = new ConcurrentHashMap<String, String>(); while(((line = reader.readLine()) != null) { if(content != null) files.put("not null"+line, "not null"+line); else

我正在尝试将此(简化)代码转换为使用Java-8流:

Map<String, String> files = new ConcurrentHashMap<String, String>();

while(((line = reader.readLine()) != null) {
      if(content != null)
        files.put("not null"+line, "not null"+line);
      else
        files.put("its null"+line, "its null"+line);
    }
reader.close();
但是上面给出了intelliJ上所有
行->行+“…”
的“循环推理”消息。什么是循环推理?这个逻辑有错误吗

我注意到一些类似的问题。但是他们建议使用接口(Map)而不是它的实现。但是
文件
在这里被声明为
映射


更新:添加更多上下文,
content
是一个保存目录名称的字符串<代码>文件是一个包含多个文件路径的映射。需要进入
文件
映射的文件路径取决于
内容
目录名是否填充

你可以这样做

reader.lines().parallel()
    .map(line -> content == null ?
            new String[]{"notnull"+line, line+"notnull"} :
            new String[]{line+"null", line+"null"})
    .collect(Collectors.toConcurrentMap(pair -> pair[0], pair -> pair[1]));

首先,将线映射到数组(或某种类型的对对象)中存储的(键、值)对,然后在收集器中再次将其拆分为键和值

另一种解决方法是为收集器引入中间变量:

Collector<String, ?, ConcurrentMap<String, String>> collector = (content != null) ?
        (Collectors.toConcurrentMap(line->"notnull"+line, line->line+"notnull")) :
        (Collectors.toConcurrentMap(line->line+"null", line->line+"null"));
Map<String, String> files = reader.lines().parallel().collect(collector);       
Collector=(内容!=null)?
(Collectors.toConcurrentMap(行->“notnull”+行,行->行+“notnull”):
(Collectors.toConcurrentMap(line->line+“null”,line->line+“null”);
映射文件=reader.lines().parallel().collect(收集器);
此解决方案(与@JanXMarek提供的解决方案不同)不分配中间数组,也不检查每个输入行的
内容


循环推理是类型推理过程中确定内子表达式类型时,必须确定外子表达式的类型,但在不知道内子表达式类型的情况下无法确定。Java-8中的类型推断可以推断,在
Stream.collect(Collectors.toConcurrentMap(line->line+“null”,line->line+“null”)
的情况下,收集器的类型是
Collector
。通常,当无法显式确定子表达式类型(这里我们谈论的是
toConcurrentMap(…)
subexpression)时,如果外部上下文是方法调用、强制转换或赋值,则可以使用外部上下文对其进行缩减。然而,这里的外部上下文是
?:
运算符,它有自己复杂的类型推理规则,因此这太多了,您应该帮助类型推理系统在某处指定显式类型。

只是一个旁注。在这种情况下,我怀疑.parallel()是否有用。如果您使用标准JavaAPI读取文件,那么下面的迭代器仍将按顺序读取文件。唯一可以并行执行的事情是转换行。出于好奇,我刚在我的电脑上试用过,没有.parallel()的话,速度大约快了10%


如果处理比读取流的输入慢一个数量级,那么并行化是有意义的,但这里不是这样。

代码示例有点不清楚。(1) 什么是“内容”变量?(2) 您正在读取单个文件的行,但将它们放入名为“文件”的地图中吗<代码>内容
是保存目录名称的字符串。2.是的,我正在从一个文本文件(基本上包含一些部分标记)中读取行,并将其附加到文件路径,这些路径将一起进入文件映射。谢谢@Jan。它怎么知道
pair
是一个字符串数组?我应该在
toConcurrentMap()中声明它吗?我认为.map()应该将字符串数组传递到
pair
变量中,但是我收到一个错误,说它没有定义。对不起,我刚刚修复了代码中的一个输入错误。但是您不需要在任何地方声明类型。Java编译器从map()操作的结果推断出它。您只需复制粘贴我的代码,它就会工作(只要定义了“reader”和“content”变量)。如果不是,你到底得到了什么错误?我仍然很好奇什么是循环推理。任何人都可以解释一下。我认为这个解决方案更具可读性和效率,因为您没有动态分配太多内存。我喜欢这个解决方案,但是,我会将三元运算符移动到
keyMapper
valueMapper
函数定义,toConcurrentMap
Hi Jan,我要明确一点,您是否尝试了
parallel()
++
toConcurrentMap()
组合与非并行+
toMap()
组合?您发现non-parallel+toMap()工作得更快?I parallel与non-parallel to ConcurrentMap,输入是一个大约100K行的文件。嗯,在不同的硬件或操作系统上,它的行为可能会有所不同。在这种情况下,系统上的并行性可能会提高10%。我的观点是.parallel()不是免费的啤酒。即使你有一个8核处理器,它也不会比93.73547%的实际情况下的非并行流表现得更好,因为艾哈迈德定律总是潜伏在某个地方。
Collector<String, ?, ConcurrentMap<String, String>> collector = (content != null) ?
        (Collectors.toConcurrentMap(line->"notnull"+line, line->line+"notnull")) :
        (Collectors.toConcurrentMap(line->line+"null", line->line+"null"));
Map<String, String> files = reader.lines().parallel().collect(collector);