Anoop Deshpande
Anoop Deshpande

Reputation: 582

Java Stream API

When we get Stream from a List of Collections, what actually happens under the hood? I found in many blogs saying that Stream doesn't store any data. If it's true, consider the snippet of code:

List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);

Stream<Integer> stream = list.stream();
list = null;
stream.forEach(i -> System.out.print(i));

As we can see, elements are accessible to stream even if List (source) is null. How is this possible?

Upvotes: -1

Views: 1748

Answers (2)

Eugene
Eugene

Reputation: 120848

This has little to do with Streams per-se, a very much simplified example:

 static class Holder {
    private final List<Integer> list;

    public Holder(List<Integer> list) {
        this.list = list;
    }

    public void show() {
        list.forEach(System.out::println);
    }
}

 Holder h = new Holder(list);
 list = null;
 h.show();

This simply re-assigns a reference, nothing more.

Upvotes: 1

Nikolas
Nikolas

Reputation: 44368

The Stream API has no idea what is inside the List until the lambda expression is performed over the first and remaining elements.

stream.forEach(i -> System.out.print(i));

The code above is nothing else than a shortcut for:

stream.forEach(new Consumer<String>() {
    @Override
    public void accept(String t) {
        System.out.println(t);
    }
});

The lambda expression is just an implemented interface, the functional interface which has only and only one method. This special interface is annotated with @FunctionalInterface and could be expressed as a lambda expression.

The point is, the method accept(String t) doesn't execute before it's actually called - the same happens for the lambda. Consider the following:

Consumer<String> consumer = i -> System.out.print(i);

// At this point the method `System.out.print(i)` remains not executed.
// Whatever expensive operation inside any lambda remains unexecuted 
// until its only method is called

stream.forEach(consumer);   // Now it encounters all the elements

For this reason, the Stream has no idea about the elements because it leaves the entire execution to the passed lambda expressions.


By the way setting list = null doesn't affect anything since the Stream<Integer> has already been created. The source is stored as Spliterator<T> in AbstractPipeline (line 123).

Upvotes: 1

Related Questions