Java Streams In-Depth : Part-1
In this artice, we will discuss in detail about Java Stream basics, filter, map and reduce operations.
Java Streams In-Depth : Part-1
In this artice, we will discuss in detail about Java Stream basics, filter, map and reduce operations.
The motivation for streams came from competitive pressure and developer envy.
- Google’s FlumeJava: Internal bulk data processing system.
- Microsoft’s LINQ/PLINQ: Extremely popular among .NET developers.
- Developer Demand: Java developers wanted similar functional capabilities.
- Business Benefits: Single-threaded applications could leverage concurrency with minimal code changes.
The Problem with Traditional Java Collections:-
// Traditional approach - verbose and error-prone
List<String> result = new ArrayList<>();
for (Employee emp : employees) {
if (emp.getDepartment().equals("Engineering") && emp.getSalary() > 70000) {
result.add(emp.getName().toUpperCase());
}
}
Collections.sort(result);
Core Architecture: Stream Processing PipelineThe Three-Stage Pipeline:-
- Source Stage: Collections provide data stream.
- Intermediate Operations: Transform data (lazy evaluation).
- Terminal Operations: Produce final results (trigger execution).
List<String> result = employees.stream() // Source
.filter(emp -> emp.getSalary() > 70000) // Intermediate
.map(Employee::getName) // Intermediate
.map(String::toUpperCase) // Intermediate
.sorted() // Intermediate
.collect(Collectors.toList()); // Terminal
Filter Operations — Selective Processing
Purpose: Select elements based on boolean predicates.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Basic filtering
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// Result: [2, 4, 6, 8, 10]
// Multiple filter conditions
List<Integer> filtered = numbers.stream()
.filter(n -> n > 3) // Greater than 3
.filter(n -> n % 2 == 0) // Even numbers
.collect(Collectors.toList());
// Result: [4, 6, 8, 10]
// Complex business filtering
List<Employee> seniorEngineers = employees.stream()
.filter(emp -> "Engineering".equals(emp.getDepartment()))
.filter(emp -> emp.getAge() > 30)
.filter(emp -> emp.getSalary() > 80000)
.collect(Collectors.toList());
Performance Characteristics:
- Time Complexity: O(n) — each element evaluated once.
- Space Complexity: O(1) for filtering predicate.
- Parallel Benefits: Excellent — independent element evaluation.
Map Operations — Data Transformation
Purpose: Transform each element to a different value or type.
// Simple transformations
List<String> upperCaseNames = employees.stream()
.map(Employee::getName)
.map(String::toUpperCase)
.collect(Collectors.toList());
// Type transformation
List<Integer> nameLengths = employees.stream()
.map(Employee::getName)
.map(String::length)
.collect(Collectors.toList());
// Complex business transformation
List<EmployeeSummary> summaries = employees.stream()
.map(emp -> new EmployeeSummary(
emp.getName(),
emp.getDepartment(),
calculateTotalCompensation(emp),
determineLevel(emp.getAge(), emp.getSalary())
))
.collect(Collectors.toList());
// Specialized numeric mappings
IntSummaryStatistics salaryStats = employees.stream()
.mapToInt(emp -> (int) emp.getSalary()) // Avoid boxing
.summaryStatistics();
System.out.println("Average salary: " + salaryStats.getAverage());
System.out.println("Max salary: " + salaryStats.getMax());
Reduce Operations — Data Aggregation
Purpose: Combine stream elements into a single result.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Basic reduction
Optional<Integer> sum = numbers.stream()
.reduce(Integer::sum);
// Result: Optional
// Reduction with identity value
Integer sumWithIdentity = numbers.stream()
.reduce(0, Integer::sum);
// Result: 15 (never Optional)
// Complex business reduction
double totalSalary = employees.stream()
.map(Employee::getSalary)
.reduce(0.0, Double::sum);
// String concatenation with reduce
String allNames = employees.stream()
.map(Employee::getName)
.reduce("Employees: ", (acc, name) -> acc + name + " ");
// Custom accumulator and combiner for parallel processing
String departmentSummary = employees.parallelStream()
.reduce("",
(partial, emp) -> partial + emp.getName() + "(" + emp.getDepartment() + ") ",
String::concat // Combiner for parallel streams
);
Specialised Reductions:
// Built-in terminal operations are optimized reductions
long count = employees.stream().count();
OptionalDouble average = employees.stream()
.mapToDouble(Employee::getSalary)
.average();
Optional<Employee> maxSalary = employees.stream()
.max(Comparator.comparing(Employee::getSalary));
boolean anyHighEarners = employees.stream()
.anyMatch(emp -> emp.getSalary() > 100000); 메타데이터
- post_id
- faa95b48a062
- slug
- java-streams-in-depth-part-1-faa95b48a062
- url
- https://medium.com/@mishra-ck/java-streams-in-depth-part-1-faa95b48a062
- canonical_url
- https://medium.com/@mishra-ck/java-streams-in-depth-part-1-faa95b48a062
- author_url
- https://medium.com/@mishra-ck
- status
- ok
- fetched_at
- 2026-07-30 03:42:02