Java · Collections · Topic 12
Integration of Collections, Lambdas and Streams
Combine collections, lambda expressions, stream pipelines, collectors, grouping, partitioning, and statistics in complete object-processing programs.
Step 1 of 12
12.1 Processing Student Objects
Connect a source collection to lambda-based stream operations and process domain objects.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectionsLambdaStreamDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(10, 15, 20, 25, 30);
List<Integer> result = numbers.stream()
.filter(number -> number % 2 == 0)
.map(number -> number * number)
.sorted()
.collect(Collectors.toList());
System.out.println(result);
}
}[100, 400, 900]| Piece | Responsibility in the pipeline |
|---|---|
| List | Stores the source values |
| stream() | Creates the stream |
| filter() lambda | Selects even numbers |
| map() lambda | Calculates squares |
| sorted() | Arranges the results |
| collect() | Creates the final result list |
import java.util.Arrays;
import java.util.List;
public class StudentProcessingDemo {
static class Student {
int enrollmentNumber;
String name;
double marks;
Student(int enrollmentNumber, String name, double marks) {
this.enrollmentNumber = enrollmentNumber;
this.name = name;
this.marks = marks;
}
public String toString() {
return enrollmentNumber + " " + name + " " + marks;
}
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(101, "Amit", 78),
new Student(102, "Neha", 92),
new Student(103, "Raj", 65),
new Student(104, "Riya", 88));
students.stream().forEach(System.out::println);
}
}101 Amit 78.0
102 Neha 92.0
103 Raj 65.0
104 Riya 88.0Check your understanding: What operation converts a collection into a sequential stream?
stream().
Step 2 of 12
12.2 Filtering Objects
Filter domain objects with a lambda predicate.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StudentFilterDemo {
static class Student {
String name; double marks;
Student(String name, double marks) { this.name = name; this.marks = marks; }
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Amit", 78), new Student("Neha", 92),
new Student("Raj", 65), new Student("Riya", 88));
List<String> eligible = students.stream()
.filter(student -> student.marks >= 75)
.map(student -> student.name)
.collect(Collectors.toList());
System.out.println("Marks at least 75: " + eligible);
}
}Marks at least 75: [Amit, Neha, Riya]Check your understanding: Which students have marks of at least 75?
Amit, Neha, and Riya.
Step 3 of 12
12.3 Transforming Objects
Transform Student objects into another representation with map().
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StudentMapDemo {
static class Student {
String name;
Student(String name) { this.name = name; }
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Amit"), new Student("Neha"),
new Student("Raj"), new Student("Riya"));
List<String> names = students.stream()
.map(student -> student.name)
.collect(Collectors.toList());
System.out.println(names);
}
}[Amit, Neha, Raj, Riya]Check your understanding: What is the output element type after mapping each student to student.name?
String.
Step 4 of 12
12.4 Sorting Objects
Sort objects by a numeric field in ascending and descending order.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class StudentSortDemo {
static class Student {
String name; double marks;
Student(String name, double marks) { this.name = name; this.marks = marks; }
public String toString() { return name + "=" + marks; }
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Amit", 78), new Student("Neha", 92),
new Student("Raj", 65), new Student("Riya", 88));
List<Student> ascending = students.stream()
.sorted(Comparator.comparingDouble(student -> student.marks))
.collect(Collectors.toList());
List<Student> descending = students.stream()
.sorted(Comparator.comparingDouble((Student student) -> student.marks).reversed())
.collect(Collectors.toList());
System.out.println("Ascending: " + ascending);
System.out.println("Descending: " + descending);
}
}Ascending: [Raj=65.0, Amit=78.0, Riya=88.0, Neha=92.0]
Descending: [Neha=92.0, Riya=88.0, Amit=78.0, Raj=65.0]Check your understanding: Which method changes an ascending comparator to descending order?
reversed().
Step 5 of 12
12.5 Filtering, Sorting and Mapping Together
Build a multi-stage object-processing pipeline.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class StudentPipelineDemo {
static class Student {
String name; double marks;
Student(String name, double marks) { this.name = name; this.marks = marks; }
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Amit", 78), new Student("Neha", 92),
new Student("Raj", 65), new Student("Riya", 88));
List<String> result = students.stream()
.filter(student -> student.marks >= 75)
.sorted(Comparator.comparingDouble((Student student) -> student.marks).reversed())
.map(student -> student.name.toUpperCase())
.collect(Collectors.toList());
System.out.println(result);
}
}[NEHA, RIYA, AMIT]Pipeline story
- Select students with marks of at least 75
- Sort selected students by marks in descending order
- Convert each selected name to uppercase
- Collect the names into a List
Check your understanding: What is the order of operations in this example?
Filter, sort descending, map to uppercase names, then collect.
Step 6 of 12
12.6 Converting a List into a Map
Collect objects into key-value pairs with Collectors.toMap().
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class StudentToMapDemo {
static class Student {
int enrollmentNumber; String name;
Student(int enrollmentNumber, String name) {
this.enrollmentNumber = enrollmentNumber; this.name = name;
}
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(101, "Amit"), new Student(102, "Neha"),
new Student(103, "Raj"), new Student(104, "Riya"));
Map<Integer, String> studentMap = students.stream()
.collect(Collectors.toMap(
student -> student.enrollmentNumber,
student -> student.name,
(existing, replacement) -> existing,
LinkedHashMap::new));
System.out.println(studentMap);
}
}{101=Amit, 102=Neha, 103=Raj, 104=Riya}Check your understanding: What problem occurs when two elements produce the same map key?
A duplicate-key exception occurs unless a merge rule is provided.
Step 7 of 12
12.7 Calculating Summary Information
Calculate count, sum, average, minimum, and maximum in one pass.
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;
public class StudentStatisticsDemo {
static class Student {
double marks;
Student(double marks) { this.marks = marks; }
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(78), new Student(92),
new Student(65), new Student(88));
DoubleSummaryStatistics statistics = students.stream()
.mapToDouble(student -> student.marks)
.summaryStatistics();
System.out.println("Count: " + statistics.getCount());
System.out.println("Total: " + statistics.getSum());
System.out.println("Average: " + statistics.getAverage());
System.out.println("Minimum: " + statistics.getMin());
System.out.println("Maximum: " + statistics.getMax());
}
}Count: 4
Total: 323.0
Average: 80.75
Minimum: 65.0
Maximum: 92.0Check your understanding: Which method converts Student objects into a numeric stream of marks?
mapToDouble().
Step 8 of 12
12.8 Grouping Objects
Group objects by a classification field.
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class EmployeeGroupingDemo {
static class Employee {
String name; String department;
Employee(String name, String department) { this.name = name; this.department = department; }
public String toString() { return name; }
}
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Amit", "IT"), new Employee("Neha", "HR"),
new Employee("Raj", "IT"), new Employee("Riya", "Accounts"));
Map<String, List<Employee>> departmentWise = employees.stream()
.collect(Collectors.groupingBy(
employee -> employee.department,
LinkedHashMap::new,
Collectors.toList()));
System.out.println(departmentWise);
}
}{IT=[Amit, Raj], HR=[Neha], Accounts=[Riya]}| Department key | Grouped value |
|---|---|
| IT | List of IT employees |
| HR | List of HR employees |
| Accounts | List of Accounts employees |
Check your understanding: What becomes the map key in the example?
The employee department.
Step 9 of 12
12.9 Counting Grouped Objects
Use a downstream collector to count each group.
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class EmployeeCountingDemo {
static class Employee {
String department;
Employee(String department) { this.department = department; }
}
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("IT"), new Employee("HR"),
new Employee("IT"), new Employee("Accounts"));
Map<String, Long> departmentCount = employees.stream()
.collect(Collectors.groupingBy(
employee -> employee.department,
LinkedHashMap::new,
Collectors.counting()));
System.out.println(departmentCount);
}
}{IT=2, HR=1, Accounts=1}Check your understanding: What is the value type in Map<String, Long>?
Long, because Collectors.counting() returns Long counts.
Step 10 of 12
12.10 Partitioning Objects
Split objects into exactly two groups using a predicate.
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class StudentPartitionDemo {
static class Student {
String name; double marks;
Student(String name, double marks) { this.name = name; this.marks = marks; }
public String toString() { return name; }
}
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Amit", 78), new Student("Neha", 92),
new Student("Raj", 65), new Student("Riya", 88),
new Student("Kavya", 35));
Map<Boolean, List<Student>> result = students.stream()
.collect(Collectors.partitioningBy(student -> student.marks >= 40));
System.out.println("Passed: " + result.get(true));
System.out.println("Failed: " + result.get(false));
}
}Passed: [Amit, Neha, Raj, Riya]
Failed: [Kavya]Check your understanding: Which key contains students whose marks are at least 40?
true.
Step 11 of 12
12.11 Removing Duplicates and Sorting
Combine distinct(), sorted(), and collect() for a clean ordered result.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class DistinctSortDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 2, 5, 1, 2, 3);
List<Integer> result = numbers.stream()
.distinct()
.sorted()
.collect(Collectors.toList());
System.out.println(result);
}
}[1, 2, 3, 5]Integrated concepts
- List supplies the data
- Stream forms the pipeline
- distinct() removes duplicates
- sorted() orders values
- collect() creates the result List
Check your understanding: What is the result for 5,2,5,1,2,3?
[1, 2, 3, 5].
Step 12 of 12
12.12 Traditional Approach versus Stream Approach
Compare imperative iteration with a declarative stream pipeline.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class TraditionalVsStreamDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(10, 15, 20, 25, 30);
List<Integer> traditional = new ArrayList<>();
for (Integer number : numbers) {
if (number % 2 == 0) {
traditional.add(number * number);
}
}
Collections.sort(traditional);
List<Integer> streamResult = numbers.stream()
.filter(number -> number % 2 == 0)
.map(number -> number * number)
.sorted()
.collect(Collectors.toList());
System.out.println("Traditional: " + traditional);
System.out.println("Stream: " + streamResult);
}
}Traditional: [100, 400, 900]
Stream: [100, 400, 900]| Traditional approach | Stream approach |
|---|---|
| Uses explicit loop and conditional statements | Uses filter(), map(), sorted(), and collect() |
| Mutation of the result list is visible | Pipeline expresses transformations declaratively |
| Often straightforward for stateful control flow | Often concise for data transformation chains |
| Easy to debug one statement at a time | Easy to read when stages have clear purposes |
Check your understanding: Do streams always replace loops?
No. Choose the form that communicates the processing clearly.