Vladimir Verstov
Vladimir Verstov

Reputation: 21

Casting with Stream API

I'm not sure why this code doesn't compile (case 1)

List list = new LinkedList<>();
List<Long> longList = list.stream()
    .map(value -> (Long) ((Map) value).get("id"))
    .collect(Collectors.toList());

but this code compile successfully (case 2)

List list = new LinkedList<>();

Stream<Long> longStream = list.stream()
    .map(value -> (Long) ((Map) value).get("id"));

List<Long> longList = longStream.collect(Collectors.toList());

and this code compile successfully to (case 3)

List<Object> list = new LinkedList<>();
List<Long> longList = list.stream()
    .map(value -> (Long) ((Map) value).get("id"))
    .collect(Collectors.toList());

My colleague suppose that this connected with

Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.

from Java SE tutorial

So in case 1 list is unbounded that's why compiler replace all types with Object.

In case 2 we create generic Stream of Long and this stream can't be unbounded. Compiler do nothing.

In case 3 we have List of Object and there is no replacing during compilation.

The question is what the real difference between this 3 cases?

Upvotes: 2

Views: 1235

Answers (1)

Peter Lawrey
Peter Lawrey

Reputation: 533530

Your List list is a raw type and this has the effect of making all the methods you call on it raw types as well, even though you might later return a generic type. i.e. you map() notional returns a Stream<Long> but the compiler only sees it as a non-generic Stream

By assigning it to a variable, you are effectively casting it to a generic.

What I suggest you do is

List<Map<String, Long>> list = new LinkedList<>();
List<Long> longList = list.stream()
    .map(value -> value.get("id"))
    .collect(Collectors.toList());

Upvotes: 3

Related Questions