A Scala Stream is like a List, except that its elements are computed lazily, in a manner similar to how a view creates a lazy version of a collection.

Because Stream elements are computed lazily, a Stream can be long … infinitely long.

Like a view, only the elements that are accessed are computed. Other than this behavior, a Stream behaves similar to a List.

Using a Stream gives you a chance to specify a huge list, and begin working with its elements.

scala> val stream = 1 #:: 2 #:: 3 #:: Stream.empty
stream: scala.collection.immutable.Stream[Int] = Stream(1, ?)

The REPL output shows that the stream begins with the number 1 but uses a ? to denote the end of the stream. This is because the end of the stream hasn’t been evaluated yet.
You can attempt to access the head and tail of the stream. The head is returned immediately, but the tail isn’t evaluated yet.

scala> val stream = (1 to 100000000).toStream
stream: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> stream.head
res0: Int = 1

scala> stream.tail
res1: scala.collection.immutable.Stream[Int] = Stream(2, ?)

scala> stream.take(3)
res0: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> stream.filter(_ < 200)
res1: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> stream.filter(_ > 200)
res2: scala.collection.immutable.Stream[Int] = Stream(201, ?)

scala> stream.map { _ * 2 }
res3: scala.collection.immutable.Stream[Int] = Stream(2, ?)


The ? symbol is the way a lazy collection shows that the end of the collection hasn’t been evaluated yet.

Transformer methods like map/ filter/ reverse, etc. are computed lazily on streams. So when transformers are called, you see the familiar ? character that indicates the end of the stream hasn’t been evaluated yet.

Note: Transformer methods are collection methods that convert a given input collection to a new output collection, based on an algorithm you provide to transform the data.

Non Transformation methods like max /size/ sum don’t fit that definition, so they attempt to operate on the Stream, and if the Stream requires more memory than you can allocate, you’ll get the java.lang.OutOfMemoryError.