The following are both meant to create a Stream of integers:
val s: Stream[Int] = 1 #:: s.map(_ + 1)
def makeStream = {
val s: Stream[Int] = 1 #:: s.map(_ + 1)
s
}
The first is fine; however the makeStream
method won't compile:
error: forward reference extends over definition of value s
val s: Stream[Int] = 1 #:: s.map(_ + 1)
^
It only compiles if we make s
a lazy val
. Why does it need to be a lazy val
in a method, but not outside?
Streams are lazy because intermediate operations are not evaluated until terminal operation is invoked. Each intermediate operation creates a new stream, stores the provided operation/function and return the new stream.
If you have a small list, loops perform better. If you have a huge list, a parallel stream will perform better. Purely thinking in terms of performance, you shouldn't use a for-each loop with an ArrayList, as it creates an extra Iterator instance that you don't need (for LinkedList it's a different matter).
How Stream is lazy? It is an important characteristic of streams because the operation on the source data is only performed when the terminal operation is initiated. It doesn't consume the source elements as in eager loading, the source elements are consumed only on demand. only.
Yes, streams are sometimes slower than loops, but they can also be equally fast; it depends on the circumstances. The point to take home is that sequential streams are no faster than loops.
Inside a class, a val
definition decompiles into an "getter" method that references a hidden class field. These "getter" methods can be self-referential (or rather, the class initializer can reference the "getter") because this is the semantics of Java methods. Note that your "outside" definition of val s
is actually wrapped in a hidden class by the REPL (this is how the REPL circumvents the restriction that a val
can't be declared at the top level).
Inside a method, the val
definition does not decompile into a "getter" method, but rather into the bytecode necessary to generate a value on the stack. A lazy val
, on the other hand, always requires a "getter" method which, as such, can be self-referential.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With