Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java add list of specific class to list of java.lang.Object works with java 8 streams - why?

public class Test {

    static List<Object> listA = new ArrayList<>();

    public static void main(final String[] args) {
        final List<TestClass> listB = new ArrayList<>();
        listB.add(new TestClass());

        // not working
        setListA(listB);

        // working
        setListA(listB.stream().collect(Collectors.toList()));

        System.out.println();
    }

    private static void setListA(final List<Object> list) {
        listA = list;
    }

}

why does it work with streams and does not work for the simple set?

like image 915
user817795 Avatar asked Jun 14 '17 14:06

user817795


People also ask

What is the benefit of stream in Java 8?

There are a lot of benefits to using streams in Java, such as the ability to write functions at a more abstract level which can reduce code bugs, compact functions into fewer and more readable lines of code, and the ease they offer for parallelization.


2 Answers

For the first case, it fails because List<TestClass> is not a subtype of List<Object>.1

For the second case, we have the following method declarations:

interface Stream<T> {
    // ...
    <R, A> R collect(Collector<? super T, A, R> collector)
}

and:

class Collectors {
    // ...
    public static <T> Collector<T, ?, List<T>> toList()
}

This allows Java to infer the generic type parameters from the context.2 In this case List<Object> is inferred for R, and Object for T.

Thus your code is equivalent to this:

Collector<Object, ?, List<Object>> tmpCollector = Collectors.toList();
List<Object> tmpList = listB.stream().collect(tmpCollector);
setListA(tmpList);

1. See e.g. here.

2. See e.g. here or here.

like image 74
Oliver Charlesworth Avatar answered Jan 04 '23 15:01

Oliver Charlesworth


This line

setListA(listB);

doesn't work because List in Java is invariant, meaning List<TestClass> doesn't extends List<Object> when TestClass extends Object. More details here

This line

setListA(listB.stream().collect(Collectors.toList()));

works because Java infer Object for Collector's generic type from this method signature setListA(final List<Object> list) and so you actually pass List<Object> there

like image 36
ikryvorotenko Avatar answered Jan 04 '23 17:01

ikryvorotenko