When you want a set number of items from the beginning of a stream, you use Stream.take. When you don’t care so much about the number, but rather the nature of the items, use Stream.takeWhile.
Stream.takeWhile starts at the beginning of the stream and applies a predicate to each item, one by one. It returns each item in a new stream until it reaches an item that does not meet the predicate:

Note that Stream.takeWhile does not return the item that fails to meet the predicate. It stops with the last item that meets the predicate.
Perhaps you have a sensor feeding you temperature readings once per minute:
import java.time.{LocalDateTime, Month}
case class Reading(
temperature: Double,
timestamp: LocalDateTime)
val readings = Stream(
Reading(89.5,
LocalDateTime.of(2015, Month.JULY, 19, 10, 0)),
Reading(90.1,
LocalDateTime.of(2015, Month.JULY, 19, 10, 1)),
Reading(89.9,
LocalDateTime.of(2015, Month.JULY, 19, 10, 2)),
Reading(90.0,
LocalDateTime.of(2015, Month.JULY, 19, 10, 3)),
Reading(90.1,
LocalDateTime.of(2015, Month.JULY, 19, 10, 4)),
Reading(-1000.0,
LocalDateTime.of(2015, Month.JULY, 19, 10, 5)),
Reading(-1000.0,
LocalDateTime.of(2015, Month.JULY, 19, 10, 6)),
Reading(90.2,
LocalDateTime.of(2015, Month.JULY, 19, 10, 7))
)
Now to get all readings up until the thermometer returns the data-not-valid indicator, employ Stream.takeWhile:
val valid = readings takeWhile { _.temperature != -1000.0 }
// valid: scala.collection.immutable.Stream[Reading] =
// Stream(
// Reading(89.5,2015-07-19T10:00),
// Reading(90.1,2015-07-19T10:01),
// Reading(89.9,2015-07-19T10:02),
// Reading(90.0,2015-07-19T10:03),
// Reading(90.1,2015-07-19T10:04)
// )
Finally, Stream.takeWhile doesn’t balk if it never reaches an element that fails to meet the predicate:
val all = Stream(1,3,4,7) takeWhile { _ < 10 }
// all: scala.collection.immutable.Stream[Int] =
// Stream(1, 3, 4, 7)
As with Stream.take, the other collection types also define takeWhile:
One reply on “Scala Saturday – The Stream.takeWhile Method”
[…] you have the same temperature sensor as the one in my post on Stream.takeWhile. This time, instead of once per minute, assume that it feeds you temperature readings once per […]