Why can't I map integers to strings when streaming from an array?

JavaFunctional ProgrammingJava 8Java Stream

Java Problem Overview


This code works (taken in the Javadoc):

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
	.map(i -> i.toString())
	.collect(Collectors.joining(", "));

This one can't be compiled:

int[] numbers = {1, 2, 3, 4};
String commaSeparatedNumbers = Arrays.stream(numbers)
	.map((Integer i) -> i.toString())
	.collect(Collectors.joining(", "));

IDEA tells me I have an "incompatible return type String in lambda expression".

Why ? And how to fix that ?

Java Solutions


Solution 1 - Java

Arrays.stream(int[]) creates an IntStream, not a Stream<Integer>. So you need to call mapToObj instead of just map, when mapping an int to an object.

This should work as expected:

String commaSeparatedNumbers = Arrays.stream(numbers)
    .mapToObj(i -> ((Integer) i).toString()) //i is an int, not an Integer
    .collect(Collectors.joining(", "));

which you can also write:

String commaSeparatedNumbers = Arrays.stream(numbers)
    .mapToObj(Integer::toString)
    .collect(Collectors.joining(", "));

Solution 2 - Java

Arrays.stream(numbers) creates an IntStream under the hood and the map operation on an IntStream requires an IntUnaryOperator (i.e a function int -> int). The mapping function you want to apply does not respect this contract and hence the compilation error.

You would need to call boxed() before in order to get a Stream<Integer> (this is what Arrays.asList(...).stream() returns). Then just call map as you did in the first snippet.

Note that if you need boxed() followed by map you probably want to use mapToObj directly.

The advantage is that mapToObj doesn't require to box each int value to an Integer object; depending on the mapping function you apply of course; so I would go with this option which is also shorter to write.

Solution 3 - Java

You can create an Integer Stream using Arrays.stream(int[]) , you can call mapToObj like mapToObj(Integer::toString).

String csn = Arrays.stream(numbers) // your numbers array
.mapToObj(Integer::toString)
.collect(Collectors.joining(", "));

Hope this helps..

Solution 4 - Java

No boxing, AFAIK, and no explosion of little strings added to the heap:

public static void main(String[] args) {
	IntStream stream = IntStream.of(1, 2, 3, 4, 5, 6);
	String s = stream.collect(StringBuilder::new, (builder, n) -> builder.append(',').append(n), (x, y) -> x.append(',').append(y)).substring(1);
	System.out.println(s);
}

Solution 5 - Java

If the purpose of this sample and question is to figure out how to map strings to a stream of ints (for example, using a stream of ints to access an index in an Array of strings), you can also use boxing, then casting to an int (which would then allow accessing the index of the array).

int[] numbers = {0, 1, 2, 3}; 
String commaSeparatedNumbers = Arrays.stream(numbers)
    .boxed()
    .map((Integer i) -> Integer.toString((int)i))
    .collect(Collectors.joining(", "));

The .boxed() call converts your IntStream (a stream of primitive ints) to a Stream (a stream of objects -- namely, Integer objects) which will then accept the return of an object (in this case, a String object) from your lambda. Here it is just a string representation of the number for demonstration purposes, but it could just as easily (and more practically) be any string object -- like the element of a string array as mentioned before.

Just thought I'd offer another possibility. In programming, there are always multiple ways of accomplishing a task. Know as many as you can, then choose the one that fits the best for the task at hand, keeping in mind performance issues, intuitiveness, clarity of code, your preferences in coding style, and the most self-documenting.

Happy coding!

Solution 6 - Java

In addition to :: operator:

String numString = numbers.stream()
  .map(String::valueOf)
  .collect(Collectors.joining(", "));

This might be important in newer Java-Versions.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDenys S&#233;guretView Question on Stackoverflow
Solution 1 - JavaassyliasView Answer on Stackoverflow
Solution 2 - JavaAlexis C.View Answer on Stackoverflow
Solution 3 - JavacodebotView Answer on Stackoverflow
Solution 4 - JavaAbuNassarView Answer on Stackoverflow
Solution 5 - Javajamesc1101View Answer on Stackoverflow
Solution 6 - JavaJanikView Answer on Stackoverflow