A [Stream](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html>)
is a sequence of elements upon which sequential and parallel aggregate operations can be performed. Any given Stream
can potentially have an unlimited amount of data flowing through it. As a result, data received from a Stream
is processed individually as it arrives, as opposed to performing batch processing on the data altogether. When combined with lambda expressions they provide a concise way to perform operations on sequences of data using a functional approach.
Example: (see it work on Ideone)
Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange");
fruitStream.filter(s -> s.contains("a"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
Output:
APPLE
BANANA
ORANGE
PEAR
The operations performed by the above code can be summarized as follows:
Stream<String>
containing a sequenced ordered [Stream](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html>)
of fruit String
elements using the static factory method [Stream.of(values)](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#of-T>...-)
.[filter()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#filter-java.util.function.Predicate->)
operation retains only elements that match a given predicate (the elements that when tested by the predicate return true). In this case, it retains the elements containing an "a"
. The predicate is given as a lambda expression.[map()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#map-java.util.function.Function->)
operation transforms each element using a given function, called a mapper. In this case, each fruit String
is mapped to its uppercase String
version using the method-reference [String::toUppercase](<https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toUpperCase-->)
.Note that the map() operation will return a stream with a different generic type if the mapping function returns a type different to its input parameter. For example on a Stream<String> calling .map(String::isEmpty) returns a Stream<Boolean>
[sorted()](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#sorted-->)
operation sorts the elements of the Stream
according to their natural ordering (lexicographically, in the case of String
).[forEach(action)](<https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#forEach-java.util.function.Consumer->)
operation performs an action which acts on each element of the Stream
, passing it to a Consumer. In the example, each element is simply being printed to the console. This operation is a terminal operation, thus making it impossible to operate on it again.Note that operations defined on the Stream are performed because of the terminal operation. Without a terminal operation, the stream is not processed. Streams can not be reused. Once a terminal operation is called, the Stream object becomes unusable.
Operations (as seen above) are chained together to form what can be seen as a query on the data.