What is a stream? Fundamentally, it’s a data structure that contains a sequence of elements, not unlike a list. And we can use it in our programs like any other data structure - we can view its components, operate on it, and combine it with other elements to make a new data structure. But there are two qualities of streams that make them particularly interesting. The first, is that the elements are not available right away - they are only available when “asked for,” i.e. a process wants to evaluate the next value in the sequence. The next interesting feature is that they are potentially infinite - the sequence need not terminate.
How do they change the way we program?
We should first say that, fundamentally, there is nothing one can do with streams that one cannot do with lists or with iteration. But the benefit of streams is that we can use them to write programs that are both efficient and elegant. We can treat a (not-yet-evaluated and potentially infinite) sequence of elements as a unit, as if it’s available all at once, and thus manipulate it in simple ways. This makes our programs easier to reason about.
Moreover, we can use a stream to represent a changing quantity in the real world; say, the state of a real-world object. If we want to write programs that deal with changing real-world objects, those programs must be able to access the current state of those objects (if we want to print a bank account balance, say) and to depict shifts into future states (update the bank account balance after a withdrawal). With a stream, we can treat a yet-unknown and potentially infinite set of future states as a single entity, and thus write simpler programs that, while incorporating the concept of ordering of events, are removed from the concept of real-world time.