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).
listtonulljust made the data unavailable in that scope.stream) you should go back study the basics