Lesson Completion
Back to course

Terminal Operations and Collectors: Gathering Results

Beginner
12 minutes4.8Java

1. The Hook (The "Byte-Sized" Intro)

In a Nutshell: Terminal operations trigger stream execution, consume stream

: forEach() (iterate), collect() (gather to collection), reduce() (combine to single value), count() (size), min/max() (extremes), anyMatch/allMatch() (test all), findFirst/findAny() (retrieve element). Collectors (Collectors class): toList/toSet/toMap(), joining() (concat strings), groupingBy() (group into Map), partitioningBy() (split boolean), summarizingInt() (statistics). Key: Terminal ops return result, close stream!

Think of harvest season. Stream operations = growing crops (filter weeds, water plants). Terminal operation = harvesting! collect() = gather into baskets. reduce() = blend into juice. forEach() = sell each fruit individually. Can't harvest twice from same field!


2. Conceptual Clarity (The "Simple" Tier)

💡 The Analogy

  • reduce(): Blender (many fruits → one smoothie)
  • collect(): Storage containers (organize harvest)
  • groupingBy(): Sorting bins (by type/size)
  • forEach(): Distribute to customers

3. Technical Mastery (The "Deep Dive")

Terminal Operations

OperationReturnsPurpose
forEachvoidSide effects
collectRMutable reduction to collection
reduceOptional<T>Immutable reduction
countlongCount elements
anyMatchbooleanAny element matches?
allMatchbooleanAll elements match?
findFirstOptional<T>First element
min/maxOptional<T>Extreme values

4. Interactive & Applied Code

java
import java.util.*; import java.util.stream.*; public class TerminalOpsCollectorsDemo { public static void main(String[] args) { demonstrateTerminalOps(); demonstrateCollectors(); demonstrateGrouping(); demonstrateStatistics(); } // Terminal operations static void demonstrateTerminalOps() { System.out.println("=== TERMINAL OPERATIONS ==="); List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // forEach numbers.stream().forEach(n -> System.out.print(n + " ")); System.out.println(); // count long count = numbers.stream().filter(n -> n % 2 == 0).count(); System.out.println("Even count: " + count); // reduce (sum) Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b); sum.ifPresent(s -> System.out.println("Sum: " + s)); // reduce with identity int product = numbers.stream().reduce(1, (a, b) -> a * b); System.out.println("Product: " + product); // min/max Optional<Integer> min = numbers.stream().min(Integer::compareTo); Optional<Integer> max = numbers.stream().max(Integer::compareTo); min.ifPresent(m -> System.out.println("Min: " + m)); max.ifPresent(m -> System.out.println("Max: " + m)); // anyMatch, allMatch, noneMatch boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0); boolean allPositive = numbers.stream().allMatch(n -> n > 0); boolean noneNegative = numbers.stream().noneMatch(n -> n < 0); System.out.println("Has even: " + hasEven); System.out.println("All positive: " + allPositive); // findFirst, findAny Optional<Integer> first = numbers.stream().filter(n -> n > 5).findFirst(); first.ifPresent(f -> System.out.println("First >5: " + f)); } // Collectors static void demonstrateCollectors() { System.out.println("\n=== COLLECTORS ==="); List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry"); // toList List<String> list = words.stream() .filter(w -> w.length() > 5) .collect(Collectors.toList()); System.out.println("List: " + list); // toSet Set<Integer> lengths = words.stream() .map(String::length) .collect(Collectors.toSet()); System.out.println("Unique lengths: " + lengths); // toMap Map<String, Integer> map = words.stream() .collect(Collectors.toMap( w -> w, // Key String::length // Value )); System.out.println("Map: " + map); // joining String joined = words.stream() .collect(Collectors.joining(", ", "[", "]")); System.out.println("Joined: " + joined); // joining with transformation String upperJoined = words.stream() .map(String::toUpperCase) .collect(Collectors.joining(" | ")); System.out.println("Upper joined: " + upperJoined); } // Grouping and Partitioning static void demonstrateGrouping() { System.out.println("\n=== GROUPING ==="); List<String> words = Arrays.asList( "apple", "apricot", "banana", "blueberry", "cherry", "cranberry", "date" ); // Group by length Map<Integer, List<String>> byLength = words.stream() .collect(Collectors.groupingBy(String::length)); System.out.println("By length: " + byLength); // Group by first letter Map<Character, List<String>> byFirstLetter = words.stream() .collect(Collectors.groupingBy(w -> w.charAt(0))); System.out.println("By first letter: " + byFirstLetter); // Group and count Map<Integer, Long> countByLength = words.stream() .collect(Collectors.groupingBy( String::length, Collectors.counting() )); System.out.println("Count by length: " + countByLength); // Partition by predicate (boolean) Map<Boolean, List<String>> partitioned = words.stream() .collect(Collectors.partitioningBy(w -> w.length() > 5)); System.out.println("Long words: " + partitioned.get(true)); System.out.println("Short words: " + partitioned.get(false)); } // Statistical collectors static void demonstrateStatistics() { System.out.println("\n=== STATISTICS ==="); List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // summingInt int sum = numbers.stream() .collect(Collectors.summingInt(Integer::intValue)); System.out.println("Sum: " + sum); // averagingInt double avg = numbers.stream() .collect(Collectors.averagingInt(Integer::intValue)); System.out.println("Average: " + avg); // summarizingInt (get all statistics at once) IntSummaryStatistics stats = numbers.stream() .collect(Collectors.summarizingInt(Integer::intValue)); System.out.println("Statistics: " + stats); System.out.println(" Count: " + stats.getCount()); System.out.println(" Sum: " + stats.getSum()); System.out.println(" Min: " + stats.getMin()); System.out.println(" Max: " + stats.getMax()); System.out.println(" Average: " + stats.getAverage()); } } // Real-world example: Employee data processing class EmployeeDataDemo { static class Employee { String name; String dept; int salary; Employee(String name, String dept, int salary) { this.name = name; this.dept = dept; this.salary = salary; } } public static void main(String[] args) { List<Employee> employees = Arrays.asList( new Employee("Alice", "Engineering", 80000), new Employee("Bob", "Sales", 60000), new Employee("Carol", "Engineering", 90000), new Employee("David", "Sales", 70000), new Employee("Eve", "Engineering", 85000) ); // Group by department Map<String, List<Employee>> byDept = employees.stream() .collect(Collectors.groupingBy(e -> e.dept)); System.out.println("By department: " + byDept.keySet()); // Average salary by department Map<String, Double> avgSalary = employees.stream() .collect(Collectors.groupingBy( e -> e.dept, Collectors.averagingInt(e -> e.salary) )); System.out.println("Avg salary by dept: " + avgSalary); // Highest paid employee Optional<Employee> highest = employees.stream() .max(Comparator.comparingInt(e -> e.salary)); highest.ifPresent(e -> System.out.println("Highest paid: " + e.name + " - $" + e.salary)); // Total payroll int totalPayroll = employees.stream() .mapToInt(e -> e.salary) .sum(); System.out.println("Total payroll: $" + totalPayroll); } }

5. The Comparison & Decision Layer

TaskMethodExample
To ListtoList()collect(Collectors.toList())
Join stringsjoining()joining(", ")
Group bygroupingBy()groupingBy(String::length)
Split booleanpartitioningBy()partitioningBy(n -> n > 5)
SumsummingInt()summingInt(Integer::intValue)
StatisticssummarizingInt()summarizingInt(...)

6. The "Interview Corner" (The Edge)

The "Killer" Interview Question: "collect() vs reduce()?" Answer:

  • collect(): Mutable reduction (modifies container)
  • reduce(): Immutable reduction (creates new values)
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // reduce(): Immutable (creates new Integer each time) int sum = numbers.stream().reduce(0, (a, b) -> a + b); // collect(): Mutable (modifies List) List<Integer> evens = numbers.stream() .filter(n -> n % 2 == 0) .collect(Collectors.toList()); // Modifies List

Use collect() for collections, reduce() for primitives/single values!

Pro-Tip: Downstream collectors:

java
// Count elements in each group Map<Integer, Long> counts = words.stream() .collect(Collectors.groupingBy( String::length, // Classifier Collectors.counting() // Downstream collector ));

Topics Covered

Java Fundamentals

Tags

#java#programming#beginner-friendly

Last Updated

2025-02-01