Understanding Java Streams
Common Operations
Douglas C. Schmidt
[email protected]
www.dre.vanderbilt.edu/~schmidt
Professor of Computer Science
Institute for Software
Integrated Systems
Vanderbilt University
Nashville, Tennessee, USA
Learning Objectives in this Part of the Lesson
• Understand Java streams structure &
functionality, e.g.
Stream source
• Fundamentals of streams
Input x
• Three streams phases
• Operations that create a stream Aggregate operation (behavior f)
Output f(x)
Aggregate operation (behavior g)
Output g(f(x))
Aggregate operation (behavior h)
2
Learning Objectives in this Part of the Lesson
• Understand Java streams structure &
functionality, e.g.
Stream source
• Fundamentals of streams
Input x
• Three streams phases
• Operations that create a stream Aggregate operation (behavior f)
• Aggregate operations in a stream
Output f(x)
Aggregate operation (behavior g)
Output g(f(x))
Aggregate operation (behavior h)
3
Operations that Create
a Java Stream
4
Operations that Create a Java Stream
• A factory method creates a stream from Stream source
some source Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
...
Aggregate operation (behavior g)
Output g(f(x))
Aggregate operation (behavior h)
See en.wikipedia.org/wiki/Factory_method_pattern
5
Operations that Create a Java Stream
• A factory method creates a stream from Stream source
some source Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...) ...
Aggregate operation (behavior g)
Array
<String> “horatio” “laertes” “Hamlet” … Output g(f(x))
Stream …
“horatio” “laertes” “Hamlet”
<String>
Aggregate operation (behavior h)
The Stream.of() factory method converts an array of T into a stream of T
See docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#of
6
Operations that Create a Java Stream
• Many factory methods create streams
collection.stream() Arrays.stream(array)
collection.parallelStream() Arrays.stream(array, start, end)
Pattern.compile(…).splitAsStream() Files.lines(file_path)
Stream.of(value1,… ,valueN) "string".chars()
StreamSupport Stream.iterate(init_value,
.stream(iterable.spliterator(), generate_expression)
false) Stream.builder().add(...).build()
... Stream.generate(supplier)
Files.list(file_path)
Files.find(file_path, max_depth,
matcher)
...
7
Operations that Create a Java Stream
• Many factory methods create streams
collection.stream() Arrays.stream(array)
collection.parallelStream() Arrays.stream(array, start, end)
Pattern.compile(…).splitAsStream() Files.lines(file_path)
Stream.of(value1,… ,valueN) "string".chars()
StreamSupport Stream.iterate(init_value,
.stream(iterable.spliterator(), generate_expression)
false) Stream.builder().add(...).build()
... Stream.generate(supplier)
Files.list(file_path)
Files.find(file_path, max_depth,
These are key factory methods matcher)
that we focus on in this course. ...
See the upcoming lesson on “Java 8Streams: Common Factory Methods”
Java Streams
Aggregate Operations
9
Java Streams Aggregate Operations
• An aggregate operation performs a behavior Stream source
on elements in a stream
Input x
Aggregate operation (behavior f)
A behavior is implemented by a lambda expression or
method reference corresponding to a functional interface
See blog.indrek.io/articles/java-8-behavior-parameterization
10
Java Streams Aggregate Operations
• An aggregate operation performs a behavior Stream source
on elements in a stream
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes",
"Hamlet", ...)
.filter(s -> toLowerCase
(s.charAt(0)) == 'h')
.map(this::capitalize)
.sorted() Stream
.forEach(System.out::println); <String> “horatio” “Hamlet”
Stream
<String> “Horatio”
Method reference “Hamlet”
See github.com/douglascraigschmidt/LiveLessons/tree/master/Java8/ex12
11
Java Streams Aggregate Operations
• An aggregate operation performs a behavior
on elements in a stream
• Some aggregate operations perform
behaviors on all elements in a stream
12
Java Streams Aggregate Operations
• An aggregate operation performs a behavior
on elements in a stream
• Some aggregate operations perform
behaviors on all elements in a stream
• Other aggregate operations perform
behaviors on some elements in a stream
13
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Aggregate operation (behavior f)
Output f(x)
Aggregate operation (behavior g)
Output g(f(x))
Aggregate operation (behavior h)
See en.wikipedia.org/wiki/Pipeline_(software)
14
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Aggregate operation (behavior f)
Output f(x)
Aggregate operation (behavior g)
Output g(f(x))
Aggregate operation (behavior h)
The output of one aggregate operation can be input into the next one in the stream.
15
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
.filter(s -> toLowerCase Aggregate operation (behavior g)
(s.charAt(0)) == 'h')
.map(this::capitalize) Output g(f(x))
.sorted()
.forEach(System.out::println); Aggregate operation (behavior h)
Java streams supports pipelining of aggregate operations via “fluent interfaces”.
See en.wikipedia.org/wiki/Fluent_interface
16
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
.filter(s -> toLowerCase Aggregate operation (behavior g)
(s.charAt(0)) == 'h')
.map(this::capitalize) Output g(f(x))
.sorted()
.forEach(System.out::println); Aggregate operation (behavior h)
A factory method that creates a stream from an array of elements
Stream Creation Operations”
See upcoming lessons on “17
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
.filter(s -> toLowerCase Aggregate operation (behavior g)
(s.charAt(0)) == 'h')
.map(this::capitalize) Output g(f(x))
.sorted()
.forEach(System.out::println); Aggregate operation (behavior h)
An aggregate operation that returns a stream
containing only elements matching the predicate
See upcoming lessons on “Stream
18 Intermediate Operations”
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
.filter(s -> toLowerCase Aggregate operation (behavior g)
(s.charAt(0)) == 'h')
.map(this::capitalize) Output g(f(x))
.sorted()
.forEach(System.out::println); Aggregate operation (behavior h)
An aggregate operation that returns a stream consisting
of results of applying a function to elements of this stream
See upcoming lessons on “Stream
19 Intermediate Operations”
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
.filter(s -> toLowerCase Aggregate operation (behavior g)
(s.charAt(0)) == 'h')
.map(this::capitalize) Output g(f(x))
.sorted()
.forEach(System.out::println); Aggregate operation (behavior h)
An aggregate operation that returns a stream
consisting of results sorted in the natural order
See docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#sorted
20
Java Streams Aggregate Operations
• Aggregate operations can be composed Stream source
to form a pipeline of processing phases
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
.filter(s -> toLowerCase Aggregate operation (behavior g)
(s.charAt(0)) == 'h')
.map(this::capitalize) Output g(f(x))
.sorted()
.forEach(System.out::println); Aggregate operation (behavior h)
An aggregate operation that performs an action on each element of the stream
Stream Terminal Operations”
See upcoming lessons on “21
Java Streams Aggregate Operations
• Java streams iterate internally (& invisibly) Stream source
between aggregate operations
Input x
Stream
.of("horatio", Aggregate operation (behavior f)
"laertes", Output f(x)
"Hamlet", ...)
.filter(s -> toLowerCase Aggregate operation (behavior g)
(s.charAt(0)) == 'h')
.map(this::capitalize) Output g(f(x))
.sorted()
.forEach(System.out::println); Aggregate operation (behavior h)
Internal iteration enhances opportunities for transparent
optimization & incurs fewer accidental complexities
See www.javabrahman.com/java-8/java-8-internal-iterators-vs-external-iterators
22
Java Streams Aggregate Operations
• In contrast, collections are iterated explicitly using loops and/or iterators.
List<String> l = new LinkedList<>
(List.of("horatio", "laertes", "Hamlet", ...));
for (int i = 0; i < l.size();)
if (toLowerCase(l.get(i).charAt(0)) != 'h’)
l.remove(i);
else {
l.set(i, capitalize(l.get(i))); i++;
}
More opportunities for accidental
Collections.sort(l); complexities & harder to optimize
for (String s : l) System.out.println(s);
See upcoming lessons on “External
23 vs. Internal Iterators in Java”
End of Understanding Java
Streams Common Operations
24