【问题标题】:Error when collecting IntStream to map收集 IntStream 以映射时出错
【发布时间】:2017-10-10 13:23:45
【问题描述】:

以下代码

String[] values = ...
.... 
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < values.length; i++) {
    map.put("X" + i, values[i]);
}

由 IntelliJ 转换为:

Map<String, Object> map = IntStream.range(0, values.length)
        .collect(Collectors.toMap(
                i -> "X" + i,
                i -> values[i],
                (a, b) -> b));

可以简写为

Map<String, Object> map = IntStream.range(0, values.length)
            .collect(Collectors.toMap(
                    i -> "X" + i,
                    i -> values[i]));

2 个流版本无法编译。

IntelliJ,提示 values[i] 中的 i 存在问题:

不兼容的类型。
必需:int
找到:java.lang.Object

编译器抱怨:

错误:(35, 17) java: 接口 java.util.stream.IntStream 中的方法 collect 不能应用于给定类型;
必需:java.util.function.Supplier,java.util.function.ObjIntConsumer,java.util.function.BiConsumer
找到:java.util.stream.Collector>
原因:无法推断类型变量 R
(实际参数列表和形式参数列表的长度不同)

谁能解释一下原因?

【问题讨论】:

  • values 是什么,您能否也包括它的声明。也对 IntelliJ 的建议,似乎不一致。只需在声明和循环之间放置一个 print map 语句。它不会再建议你替换为collect了。
  • String[] 值 = ...
  • 我想Collectors 不支持原语,这可能是 lambda 转换为 Object 的原因,因为 boxed() 修复了它。
  • 无论如何你都应该向他们提交错误

标签: java intellij-idea java-8 java-stream javac


【解决方案1】:

不太确定 intelliJ 的建议在那里会如何发挥作用,似乎不一致。放一个

System.out.print(map);

声明和循环之间的声明,然后它不会建议您进一步替换为collect


在使用IntStream#collect 时,编译失败的原因是collect 方法的实现需要三个指定的参数在错误中也可见,而

Collectors.toMap(i -> "X" + i, i -> values[i])

只会产生一个Collector 类型的参数。


将表达式转换为更好的方法是

  • 要么使用forEach

    Map<String, Object> map;
    IntStream.range(0, values.length).forEach(i -> map.put("X" + i, values[i]));
    
  • 或使用boxed()IntStream 转换为Stream&lt;Integer&gt; 为:-

    Map<String, Object> map = IntStream.range(0, values.length).boxed()
               .collect(Collectors.toMap(i -> "X" + i, i -> values[i], (a, b) -> b));
    
  • 或者按照@Holger 的建议,您可以避免使用forEach 和装箱开销,并修改构造以使用IntStream.collect 三参数变体:-

    Map<String, Object> map = IntStream.range(0, values.length)
               .collect(HashMap::new, (m,i) -> m.put("X"+i,values[i]), Map::putAll);
    

【讨论】:

  • 我会使用第一个。第二个,boxed 将导致在Integer 和 int 之间有太多的框和取消框。
  • 虽然您的解决方案是有效的,但它们并没有回答我的问题:为什么它不能编译?
  • @msayag 已编辑。虽然考虑日志是不言自明的。另一方面,使用 boxed 将 IntStream 转换为 Stream 并且 collect 在该类中被重载以接受您传递的 Collector
  • 使用三参数变体:Map&lt;String, Object&gt; map = IntStream.range(0, values.length) .collect(HashMap::new, (m,i) -&gt; m.put("X"+i,values[i]), Map::putAll); 避免了没有forEach 代码味道的装箱开销。
  • @Holger 感谢您的洞察力。更新。以前根据 IntelliJ 的建议建议的 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-28
  • 2020-01-14
  • 2019-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多