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.
Arrays.stream(la)
executes the method public static LongStream stream(long[] array)
which produces a LongStream
. LongStream
's map
method returns a LongStream
(ie 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.
The code only looks the same. The method Arrays.stream
that is being called is actually different in both cases:
stream(long[])
which returns a LongStream
. This is a primitive specialization of a stream for long
elements. stream(T[])
(where T = String
here) wich returns a Stream<String>
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 -----^
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()
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.