3

Can anyone explain to me why the following does not work:

long la[] = new long[] {1,2,3};
Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());

When this does:

String la[] = new String[] {"1","2","3"};
Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());

The former gives a compilation error while the latter does not. The compilation error is so cryptic (Eclipse) that I cannot make sense of it.

3 Answers 3

2

Arrays.stream(la) executes the method public static LongStream stream(long[] array) which produces a LongStream. LongStream's map method returns a LongStream (i.e. each long element of the source LongStream is mapped to a long element in the target LongStream). LongStream doesn't have a collect method that accepts a single argument, which is why collect(Collectors.toSet()) doesn't pass compilation.

It should work if you use mapToObj :

Set<Long> set = Arrays.stream(la).mapToObj(Long::valueOf).collect(Collectors.toSet());

Your second snippet works since here Arrays.stream produces a Stream of a reference type (Stream<String>) whose map method produces another Stream of a reference type (Stream<Long> in your case). Here, Stream has a collect method that accepts a single argument - collect(Collector<? super T, A, R> collector) - so collect(Collectors.toSet()) works.

Sign up to request clarification or add additional context in comments.

8 Comments

This will solve the problem but it doesn't explain why the first snippet doesn't compile though.
Shorter: Arrays.stream(la).boxed().collect(Collectors.toSet());
LongUnaryOperator o = Long::valueOf compiles fine. This is not the problem.
It is not be a problem to provide a function long -> Long when it expects a function long -> long, due to autoboxing (you will just do unecessary conversions). The problem is with the collect call.
I ended up using .boxed() which is shorter and more explict than mapToObj(). But thanks a lot for the explanation, it made a lot of sense.
|
2

The code only looks the same. The method Arrays.stream that is being called is actually different in both cases:

On a Stream<String>, you can call map and return a Stream<R> based on the return type of the mapper. But on a LongStream, map will always return a LongStream, that is the primitive specialization. What happens is that Long::valueOf will turn your long element into a Long object and then it will be automatically unboxed into a long; effectively, the call is doing nothing except a box / unbox.

Then the problem appears on the collect call.

  • LongStream.collect expects 3 arguments
  • Stream.collect has a 3 argument method but also a 1 argument method, which is the one you call with .collect(Collectors.toSet());.

So you can't call .collect(Collectors.toSet()); on a LongStream. This won't compile: it expects 3 arguments.

What you can do is call mapToObj instead of map on the LongStream: this method declares to return a Stream<R> (instead of a LongStream) from the return type of the mapper. In this case, the mapper is Long::valueOf that returns a Long object so it will return a Stream<Long>.

To recap:

  long la[] = new long[] {1,2,3};
  Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());
//^--LongStream----^^---LongStream----^^     error

  String la[] = new String[] {"1","2","3"};
  Arrays.stream(la).map(Long::valueOf).collect(Collectors.toSet());
//^-Stream<String>-^^--Stream<Long>--^^---- successful call -----^

  long la[] = new long[] {1,2,3};
  Arrays.stream(la).mapToObj(Long::valueOf).collect(Collectors.toSet());
//^--LongStream----^^-----Stream<Long>-----^^---- successful call -----^

1 Comment

Thanks for your answer!
0

To answer why the first one doesn't compile, this creates a LongStream:

Arrays.stream(la)

This takes each long, creates a Long wrapper, then unboxes it back to long. Stream is still a LongStream:

.map(Long::valueOf)

This passes a single parameter to LongStream.collect, which fails because LongStream.collect required 3 parameters:

.collect(Collectors.toSet())

You need to change the map to mapToObj if you want to change the LongStream into a Stream<Long> (or call LongStream.boxed())

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.