Aspects of Streams, Revisited – Streams
Aspects of Streams, Revisited
We now take a closer look at the following aspects pertaining to streams:
- Stream mapping
- Lazy execution
- Short-circuit evaluation
- Stateless and stateful operations
- Order of intermediate operations
- Non-interfering and stateless behavioral parameters of stream operations
Table 16.3, p. 938, summarizes certain aspects of each intermediate operation. Table 16.4, p. 939, summarizes the intermediate operations provided by the Stream API.
Stream Mapping
Each intermediate operation returns a new stream—that is, it maps the elements of its input stream to an output stream. Intermediate operations can thus be easily recognized. Having a clear idea of the type of the new stream an intermediate operation should produce aids in customizing the operation with an appropriate implementation of its behavioral parameters. Typically, these behavioral parameters are functional interfaces.
Because intermediate operations return a new stream, calls to methods of intermediate operations can be chained, so much so that code written in this method chaining style has become a distinct hallmark of expressing queries with streams.
In Example 16.3, the stream pipeline represents the query to create a list with titles of pop music CDs in a given list of CDs. Stream mapping is illustrated at (1). The initial stream of CDs (Stream<CD>) is first transformed by an intermediate operation (filter()) to yield a new stream that has only pop music CDs (Stream<CD>), and this stream is then transformed to a stream of CD titles (Stream<String>) by a second intermediate operation (map(), p. 921). The stream of CD titles is reduced to the desired result (List<CD>) by the terminal operation (collect()).
In summary, the type of the output stream returned by an intermediate operation need not be the same as the type of its input stream.
Example 16.3 Stream Mapping and Loop Fusion
import java.util.List;
public class StreamOps {
public static void main(String[] args) {
// Query: Create a list with titles of pop music CDs.
// (1) Stream Mapping:
List<CD> cdList1 = CD.cdList;
List<String> popCDs1 = cdList1
.stream() // Initial stream: Stream<CD>
.filter(CD::isPop) // Intermediate operation: Stream<CD>
.map(CD::title) // Intermediate operation: Stream<String>
.toList(); // Terminal operation: List<String>
System.out.println(“Pop music CDs: ” + popCDs1);
System.out.println();
// (2) Lazy Evaluation:
List<CD> cdList2 = CD.cdList;
List<String> popCDs2 = cdList2
.stream() // Initial stream: Stream<CD>
.filter(cd -> { // Intermediate operation: Stream<CD>
System.out.println(“Filtering: ” + cd // (3)
+ (cd.isPop() ? ” is pop CD.” : ” is not pop CD.”));
return cd.isPop();
})
.map(cd -> { // Intermediate operation: Stream<String>
System.out.println(“Mapping: ” + cd.title()); // (4)
return cd.title();
})
.toList(); // Terminal operation: List<String>
System.out.println(“Pop music CDs: ” + popCDs2);
}
}
Output from the program:
Pop music CDs: [Java Jive, Lambda Dancing]
Filtering: <Jaav, “Java Jive”, 8, 2017, POP> is pop CD.
Mapping: Java Jive
Filtering: <Jaav, “Java Jam”, 6, 2017, JAZZ> is not pop CD.
Filtering: <Funkies, “Lambda Dancing”, 10, 2018, POP> is pop CD.
Mapping: Lambda Dancing
Filtering: <Genericos, “Keep on Erasing”, 8, 2018, JAZZ> is not pop CD.
Filtering: <Genericos, “Hot Generics”, 10, 2018, JAZZ> is not pop CD.
Pop music CDs: [Java Jive, Lambda Dancing]
Leave a Reply