使用流有条件地填充地图 - Java 8

时间:2016-03-28 02:03:24

标签: 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
        files.put("its null"+line, "its null"+line);
    }
reader.close();

以下是我尝试的内容:

files = reader.lines().parallel().collect((content != null)?
                (Collectors.toConcurrentMap(line->"notnull"+line, line->line+"notnull")) :                                              
                (Collectors.toConcurrentMap(line->line+"null", line->line+"null")));

但是上面给出了一个&#34;循环推理&#34;智能上所有line->line+"..."的消息。什么是循环推理?这个逻辑中有错误吗?

我在SO上注意到了一些类似的问题。但他们建议使用接口(Map)而不是其实现。但files此处声明为Map

更新:添加更多上下文,content是一个包含目录名称的String。 files是一个包含多个文件路径的地图。需要进入files映射的文件路径取决于content目录名是否已填充。

3 个答案:

答案 0 :(得分:7)

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

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);       

此解决方案(与@JanXMarek提供的解决方案不同)不分配中间数组,也不检查每个输入行的content

循环推理是类型推断过程中的情况,当确定内部子表达式的类型时,必须确定外部子表达式的类型,但是在不知道内部子表达式的类型的情况下无法确定。 Java-8中的类型推断可以推断出在Stream<String>.collect(Collectors.toConcurrentMap(line->line+"null", line->line+"null"))的情况下,收集器的类型是Collector<String, ?, ConcurrentMap<String, String>>。通常,当无法显式确定子表达式(此处我们关于toConcurrentMap(...)子表达式)时,如果外部上下文是方法调用,强制转换或赋值,则可以使用外部上下文来减少它。然而,外部上下文是?:运算符,它有自己的复杂类型推理规则,所以这变得太多了,你应该帮助类型推断系统在某处指定显式类型。

答案 1 :(得分:4)

你可以这样做

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]));

首先,您行映射到存储在数组(或某种Pair对象)中的(key,value)对,然后在收集器中再次拆分它成为一个关键和一个价值。

答案 2 :(得分:1)

只是旁注。我怀疑.parallel()在这种情况下有任何好处。如果您使用标准Java API来读取文件,则下面的迭代器仍将按顺序读取文件。将要并行执行的唯一事情就是改变线条。出于好奇,我只是在我的电脑上尝试过它,没有.parallel(),它的速度提高了大约10%。

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

相关问题