"After all, the engineers only needed to refuse to fix anything, and modern industry would grind to a halt." -Michael Lewis

Enable Massive Growth

The Java Stream API: An Introduction to Collecting Results

Oct 2018

You can view the sample code associated with this post on GitHub.

Calling collect(..) on a stream terminates a stream into a collection. We've already seen that calling collect(Collectors.toList()) moves your stream into a List<T>, but you can also collect into a set. If we take our familiar collection of names in a String collection:

public static List<String> getListOfNames() {
    List<String> names = new ArrayList<>();


    return names;

We can make a set out of them like so:

public void collect_toSet() {
    Set<String> allJNames = names.stream().filter(name -> name.startsWith("J")).collect(Collectors.toSet());


You can join a Stream without using a delimiter:

public void collect_joining() {
    String allNamesJoined = names.stream().collect(Collectors.joining());


Or you can include a delimiter:

public void collect_joinWithDelimiter() {
    String commaDelimitedNames = names.stream().collect(Collectors.joining(","));


Let's move into a slightly more involved example. In a POJO class like so:

public class SimplePair {

    private String name;
    private int id;

    public String getName() {
        return name;

    public void setName(String name) {
        this.name = name;

    public int getId() {
        return id;

    public void setId(int id) {
        this.id = id;

    public String toString() {
        return "name-" + name + ",id-" + id;

And where we create pairs that have (id: 1, name: pair1), (id: 2, name: pair2)....

public static List<SimplePair> generateSimplePairs(int numToGenerate) {
    List<SimplePair> pairs = new ArrayList<>();
    for (int i = 1; i <= numToGenerate; i++) {
        SimplePair pair = new SimplePair();

        pair.setName("pair" + i);

    return pairs;

We can then collect after a call to map(..), as map continues along the stream:

public void collect_mapToString() {
    List<SimplePair> twoPairs = TestUtils.generateSimplePairs(2);

    String semiColonDelimited = twoPairs.stream().map(Objects::toString).collect(Collectors.joining(";"));

    assertEquals("name-pair1,id-1;name-pair2,id-2", semiColonDelimited);

Finally, we can collect a summary of statistics about certain primitive types. If we wanted statistics about the ids of the collection, we could get them with a call to collect(Collectors.summarizingInt(SimplePair::getId)):

public void collectStatistics() {
    IntSummaryStatistics statistics = simplePairs.stream().collect(Collectors.summarizingInt(SimplePair::getId));

    assertEquals(5, statistics.getCount());
    assertEquals(5, statistics.getMax());
    assertEquals(1, statistics.getMin());
    assertEquals(15, statistics.getSum());

Nick Fisher is a software engineer in the Pacific Northwest. He focuses on building highly scalable and maintainable backend systems.