11

The following code

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

is converted by IntelliJ to:

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

which can be shortened to

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

The 2 stream versions don't compile.

IntelliJ, hints that there is an issue with the i in values[i]:

Incompatible types.
Required: int
Found: java.lang.Object

The compiler complains:

Error:(35, 17) java: method collect in interface java.util.stream.IntStream cannot be applied to given types;
required: java.util.function.Supplier,java.util.function.ObjIntConsumer,java.util.function.BiConsumer
found: java.util.stream.Collector>
reason: cannot infer type-variable(s) R
(actual and formal argument lists differ in length)

Can anyone explain why?

Naman
  • 27,789
  • 26
  • 218
  • 353
msayag
  • 8,407
  • 4
  • 30
  • 29
  • what is `values`, could you include its declaration as well. Also onto IntelliJ's suggestion, seems inconsistent. Just put a print `map` statement between the declaration and loop. It won't suggest you to *replace with collect* anymore. – Naman Oct 10 '17 at 13:39
  • 1
    String[] values = ... – msayag Oct 10 '17 at 13:50
  • 1
    I imagine `Collector`s don't support primitives, and that could be why the lambdas are converted to `Object`, because `boxed()` fixes it. – Jacob G. Oct 11 '17 at 00:37
  • You should totally file a bug with them anyways – everton Oct 11 '17 at 03:49
  • Filed: https://youtrack.jetbrains.com/issue/IDEA-180417 – msayag Oct 11 '17 at 13:11

1 Answers1

10

Not very certain about how intelliJ's suggestion would work there, it seems inconsistent. Just put a

System.out.print(map);

statement between the declaration and loop and then it won't suggest you Replace with collect any further.


While using the IntStream#collect, the compilation fails for the reason that implementation of collect method expects three specified arguments as visible in the error as well while the

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

would result in only a single argument of type Collector.


Better way to convert the expression would be though to

  • either use forEach

    Map<String, Object> map;
    IntStream.range(0, values.length).forEach(i -> map.put("X" + i, values[i]));
    
  • Or use boxed() to convert the IntStream to Stream<Integer> as:-

    Map<String, Object> map = IntStream.range(0, values.length).boxed()
               .collect(Collectors.toMap(i -> "X" + i, i -> values[i], (a, b) -> b));
    
  • Or as suggested by @Holger, you can avoid using forEach and boxing overhead and modify the construct to make use of the IntStream.collect three-arg variant as:-

    Map<String, Object> map = IntStream.range(0, values.length)
               .collect(HashMap::new, (m,i) -> m.put("X"+i,values[i]), Map::putAll);
    
Naman
  • 27,789
  • 26
  • 218
  • 353
  • I would use the first one. The second one, with that `boxed` will lead to too many boxes and unboxes between `Integer` and int. – Shirkam Oct 10 '17 at 14:02
  • While your solutions are valid, they don't answer my question: why doesn't it compile? – msayag Oct 10 '17 at 14:36
  • @msayag Edited. Was considering the log as self-explanatory though. Using boxed on the other hand converts the `IntStream` to `Stream` and the `collect` is overloaded in that class to accept your `Collector` passed. – Naman Oct 10 '17 at 16:03
  • 4
    Use the three-arg variant: `Map map = IntStream.range(0, values.length) .collect(HashMap::new, (m,i) -> m.put("X"+i,values[i]), Map::putAll);` avoids the boxing overhead without the `forEach` code smell. – Holger Oct 11 '17 at 09:32
  • @Holger Thanks for the insight. Updated. Suggested formerly based on the IntelliJ's suggestions :) – Naman Oct 11 '17 at 10:17