3

I was trying to something pretty simple, but it fails on compilation, and I can't understand who

I have a list of headers, I need to convert it to Map<Index, String> meaning the key (index) and the value is the header name

I know how to make it with for each, but I want to have it in Collectors.to map any help would be appreciated

final String[] headerDisplayName = getHeaderDisplayName(harmonizationComponentDataFixRequest);

IntStream.of(0, headerDisplayName.length).collect(Collectors.toMap(Function.identity(), index-> headerDisplayName[index]));
Naman
  • 27,789
  • 26
  • 218
  • 353
Hard Worker
  • 995
  • 11
  • 33

2 Answers2

5

You can use range method in combination with boxed method of IntStream.

(When you use the of method like in your example, only 0 and the size of the array are in this stream. In addition this would lead to an ArrayIndexOutOfBoundsException)

A possible solution would look like this (first parameter of the range method is included, the second parameter is excluded)

Map<Integer, String> map = IntStream.range(0, headerDisplayName.length)
        .boxed()
        .collect(Collectors.toMap(
                Function.identity(), 
                i -> headerDisplayName[i])
        );
Lavish Kothari
  • 2,211
  • 21
  • 29
csalmhof
  • 1,820
  • 2
  • 15
  • 24
  • To know the reason behind why `boxed()` solved this, check [my answer](https://stackoverflow.com/a/67800492/2346131) for this question. – Lavish Kothari Jun 02 '21 at 07:22
2

Adding to the @csalmhof's answer, I think it's to explain here why using boxed is working.

If you don't use boxed() method and simply write the following:

Map<Integer, String> map = IntStream.range(0, headerDisplayName.length)
        .collect(Collectors.toMap(
                Function.identity(),
                index -> headerDisplayName[index])
        );

Java will have to take index as of type Object and there's no implicit conversion that can happen and so you'll get error.

But if you put boxed() like in the following code, you won't get error:

Map<Integer, String> map = IntStream.range(0, headerDisplayName.length)
        .boxed()
        .collect(Collectors.toMap(
                Function.identity(),
                index -> headerDisplayName[index])
        );

you're not getting error here because java interprets index as an Integer and there's implicit casting happening from Integer to int.

A good IDE can help you with this type of explanation. In IntelliJ if you press ctrl + space after keeping your cursor on index (with Eclipse key-map enabled) you will get the following without boxed().

enter image description here

And this is what you get when you've boxed() placed. enter image description here

I hope this clarifies why using boxed() is saving you from compilation error. Also, you can use this thing in future to find actual type of parameter in lambda which can be helpful in case cases (one of the case is the one that OP pointed out)

Lavish Kothari
  • 2,211
  • 21
  • 29
  • @BarakKedem The fundamental error is that there is no such `IntStream#collect(Collector)` method. There is, however, a `Stream#collect(Collector)` method and that's why calling `IntStream#boxed()` works, because it returns a `Stream`. The IDE error shown in this answer is "confused", probably by the fact that the `IntStream#collect(Supplier,ObjIntConsumer,BiConsumer)` method exists. So the compiler sees there is indeed a method named `collect` and moves on to trying to parse the argument passed to the method. But since you're creating a `Collector` there's a problem and it ... – Slaw Jun 02 '21 at 15:14
  • ... can't infer the generic types. So it defaults to `Object` for `toMap` which means it infers the argument(s) to be a `Function`. That makes `index` an `Object` and thus the error when trying to use it to access an array element. But if you were to simply change `index -> headerDisplayName[index]` to `(Integer index) -> headerDisplayName[index]` that part of the code would start working. And then you would see that the underlying error is trying to pass a `Collector` to the `IntStream#collect(Supplier,ObjIntStream,BiConsumer)` method. – Slaw Jun 02 '21 at 15:14