๐ŸŽ“ A1Learner
๐Ÿ”
0 of 40 lessons completed

Java Collectors

A collector gathers the values left in a stream into one result. Collectors is the helper class that supplies the common gathering rules.

toList gathers the survivors

The filter keeps the passing scores. toList collects them into a new list that prints as one line.

import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<Integer> scores = List.of(45, 82, 61, 90);
    List<Integer> passing = scores.stream()
        .filter(score -> score >= 60)
        .collect(Collectors.toList());
    System.out.println(passing);
  }
}

joining builds one string

joining places the separator between each pair of names. The whole stream becomes a single line of text.

import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<String> names = List.of("Ana", "Ben", "Cy");
    String line = names.stream().collect(Collectors.joining(", "));
    System.out.println(line);
  }
}

toMap pairs names with scores

toMap takes the name as each key and the score as each value. A sorted copy of the keys fixes the printed order.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<Student> students = List.of(
        new Student("Cy", 88),
        new Student("Ana", 92),
        new Student("Ben", 75));
    Map<String, Integer> byName = students.stream()
        .collect(Collectors.toMap(student -> student.name, student -> student.score));
    List<String> keys = new ArrayList<>(byName.keySet());
    Collections.sort(keys);
    for (String key : keys) {
      System.out.println(key + "=" + byName.get(key));
    }
  }
}
class Student {
  String name;
  int score;
  Student(String name, int score) {
    this.name = name;
    this.score = score;
  }
}

groupingBy counts by first letter

The grouping rule reads the first letter of each word. counting totals the words inside each letter group.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<String> words = List.of("apple", "ant", "banana", "bear", "cat");
    Map<String, Long> counts = words.stream()
        .collect(Collectors.groupingBy(word -> word.substring(0, 1), Collectors.counting()));
    List<String> keys = new ArrayList<>(counts.keySet());
    Collections.sort(keys);
    for (String key : keys) {
      System.out.println(key + "=" + counts.get(key));
    }
  }
}

summingInt totals in one pass

summingInt takes the score from each student and adds it. The collector answers the grand total directly.

import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<Student> students = List.of(
        new Student("Ana", 92),
        new Student("Ben", 75),
        new Student("Cy", 88));
    int total = students.stream()
        .collect(Collectors.summingInt(student -> student.score));
    System.out.println(total);
  }
}
class Student {
  String name;
  int score;
  Student(String name, int score) {
    this.name = name;
    this.score = score;
  }
}

Example

import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<Student> students = List.of(
        new Student("Ana", 92),
        new Student("Ben", 75),
        new Student("Cy", 88));
    List<String> topNames = students.stream()
        .filter(student -> student.score >= 80)
        .map(student -> student.name)
        .collect(Collectors.toList());
    System.out.println(topNames);
    String line = topNames.stream().collect(Collectors.joining(" and "));
    System.out.println(line);
    int topTotal = students.stream()
        .filter(student -> student.score >= 80)
        .collect(Collectors.summingInt(student -> student.score));
    System.out.println(topTotal);
  }
}
class Student {
  String name;
  int score;
  Student(String name, int score) {
    this.name = name;
    this.score = score;
  }
}

Key points

  • Collectors.toList gathers the surviving values into a new list.
  • Collectors.joining builds one string and places a separator between the values.
  • Collectors.toMap pairs each key taken from a value with a value taken from it.
  • Collectors.groupingBy places values into groups chosen by a rule.
  • groupingBy with counting counts the members of each group.
  • Collectors.summingInt adds an int taken from each value.
  • A parallel stream may split the work across threads, and the order of side effects is not promised.

In this example, toList gathers the names of the students scoring 80 or more. joining turns that list into one line with and between the names. summingInt then totals the same filtered scores into 180.

Note

This course keeps its stream exhibits sequential, so every printed line stays exact.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Which collector builds one string from a stream of text values?