Flat Mapping Adapter for Downstream Collectors

The flatMapping() method of the Collectors class encapsulates a mapper function and a downstream collector to create an adapter for a flat mapping operation. (See also the flatMap() intermediate operation, p. 924.)

Click here to view code image

static <T,U,A,R> Collector<T,?,R> flatMapping(
       Function<? super T,? extends Stream<? extends U>> mapper,
       Collector<? super U,A,R>                          downstream)

Returns a Collector that applies the specified mapper function to input elements of type T and provides the mapped results of type U to the downstream collector that accumulates them into results of type R.

That is, the method adapts a downstream collector accepting elements of type U to one accepting elements of type T by applying a flat mapping function to each input element before accumulation, where type parameter A is the intermediate accumulation type of the downstream collector.

The flat mapping function maps an input element to a mapped stream whose elements are flattened (p. 924) and passed downstream. Each mapped stream is closed after its elements have been flattened. An empty stream is substituted if the mapped stream is null.

Given the lists of CDs below, we wish to find all unique CD titles in the lists. A stream of CD lists is created at (1). Each CD list is used to create a stream of CDs whose elements are flattened into the output stream of CDs at (2). Each CD is then mapped to its title at (3), and unique CD titles are accumulated into a set at (4). (Compare this example with the one in Figure 16.9, p. 925, using the flatMap() stream operation.)

Click here to view code image

// Given lists of CDs:
List<CD> cdListA = List.of(CD.cd0, CD.cd1);
List<CD> cdListB = List.of(CD.cd0, CD.cd1, CD.cd1);
// Find unique CD titles in the given lists:
Set<String> set =
  Stream.of(cdListA, cdListB)                         // (1) Stream<List<CD>>
        .collect(Collectors.flatMapping(List::stream, // (2) Flatten to Stream<CD>
             Collectors.mapping(CD::title,            // (3) Stream<String>
                 Collectors.toSet())));               // (4) Set<String>

Set of unique CD titles in the CD lists:

[Java Jive, Java Jam]

The collectors returned by the flatMapping() method are designed to be used in multilevel grouping operations (p. 987), such as downstream from groupingBy() or partitionBy() operations. Example 16.13 illustrates such a use with the groupingBy() operation.

In Example 16.13, the class RadioPlaylist at (1) represents a radio station by its name and a list of CDs played by the radio station. Three CD lists are constructed at (2) and used to construct three radio playlists at (3). The radio playlists are stored in a common list of radio playlists at (4). A query is formulated at (5) to find the unique titles of CDs played by each radio station. Referring to the line numbers in Example 16.13:

(6) A stream of type Stream<RadioPlaylist> is created from the list radioPlaylists of type RadioPlaylist.

(7) The radio playlists are grouped according to the name of the radio station (String).

(8) Each radio playlist of type RadioPlaylist is used as the source of a stream, which is then flattened into the output stream of type Stream<CD> by the flatMapping() operation.

(9) Each CD in the stream is mapped to its title.

(10) Each unique CD title is accumulated into the result set of each radio station (Set<String>).

The query at (5) uses four collectors. The result map has the type Map<String, List<String>>. The output shows the unique titles of CDs played by each radio station.

Example 16.13 Flat mapping

Click here to view code image

import java.util.List;
// Radio station with a playlist.
public class RadioPlaylist {                                               // (1)
  private String radioStationName;
  private List<CD> Playlist;
  public RadioPlaylist(String radioStationName, List<CD> cdList) {
    this.radioStationName = radioStationName;
    this.Playlist = cdList;
  }
  public String getRadioStationName() { return this.radioStationName; }
  public List<CD> getPlaylist() { return this.Playlist; }
}

Click here to view code image

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class CollectorsFlatMapping {
  public static void main(String[] args) {
    // Some lists of CDs:                                                     (2)
    List<CD> cdList1 = List.of(CD.cd0, CD.cd1, CD.cd1, CD.cd2);
    List<CD> cdList2 = List.of(CD.cd0, CD.cd0, CD.cd3);
    List<CD> cdList3 = List.of(CD.cd0, CD.cd4);
    // Some radio playlists:                                                  (3)
    RadioPlaylist pl1 = new RadioPlaylist(“Radio JVM”, cdList1);
    RadioPlaylist pl2 = new RadioPlaylist(“Radio JRE”, cdList2);
    RadioPlaylist pl3 = new RadioPlaylist(“Radio JAR”, cdList3);
    // List of radio playlists:                                               (4)
    List<RadioPlaylist> radioPlaylists = List.of(pl1, pl2, pl3);
    // Map of radio station names and set of CD titles they played:           (5)
    Map<String, Set<String>> map = radioPlaylists.stream()                 // (6)
        .collect(Collectors.groupingBy(RadioPlaylist::getRadioStationName, // (7)
             Collectors.flatMapping(rpl -> rpl.getPlaylist().stream(),     // (8)
                 Collectors.mapping(CD::title,                             // (9)
                     Collectors.toSet()))));                               // (10)
    System.out.println(map);
  }
}

Output from the program (edited to fit on the page):

Click here to view code image

{Radio JAR=[Hot Generics, Java Jive],
 Radio JVM=[Java Jive, Lambda Dancing, Java Jam],
 Radio JRE=[Java Jive, Keep on Erasing]}

Leave a Reply

Your email address will not be published. Required fields are marked *