Reputation: 582
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
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
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