Skip to main content

Command Palette

Search for a command to run...

Java 8 Stream API in depth

Updated
β€’4 min readβ€’View as Markdown

The Stream API in Java 8 is a powerful tool for processing sequences of data in a functional programming style. It allows operations like filtering, mapping, and reducing on collections and other data sources.

Here's a comprehensive, in-depth example of using the Stream API, including explanations of key methods and a real-world use case.

Scenario: Employee Management

Imagine a system that manages employees. We want to:

  1. Filter employees by department.

  2. Find employees earning more than a threshold salary.

  3. Group employees by department.

  4. Calculate the average salary of employees in each department.

  5. Sort employees by name.

  6. Find the employee with the highest salary.

Example Code:

import java.util.*;
import java.util.stream.*;

class Employee {
    private int id;
    private String name;
    private String department;
    private double salary;

    public Employee(int id, String name, String department, double salary) {
        this.id = id;
        this.name = name;
        this.department = department;
        this.salary = salary;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getDepartment() {
        return department;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return "Employee{id=" + id + ", name='" + name + "', department='" + department + "', salary=" + salary + "}";
    }
}

public class StreamAPIExample {
    public static void main(String[] args) {
        // Create a list of employees
        List<Employee> employees = Arrays.asList(
                new Employee(1, "Alice", "HR", 45000),
                new Employee(2, "Bob", "Engineering", 70000),
                new Employee(3, "Charlie", "Engineering", 80000),
                new Employee(4, "David", "HR", 50000),
                new Employee(5, "Eve", "Finance", 60000),
                new Employee(6, "Frank", "Finance", 55000)
        );

        // 1. Filter employees by department (Engineering)
        List<Employee> engineeringEmployees = employees.stream()
                .filter(e -> e.getDepartment().equals("Engineering"))
                .collect(Collectors.toList());

        // 2. Find employees earning more than 60,000
        List<Employee> highEarners = employees.stream()
                .filter(e -> e.getSalary() > 60000)
                .collect(Collectors.toList());

        // 3. Group employees by department
        Map<String, List<Employee>> employeesByDept = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));

        // 4. Calculate the average salary in each department
        Map<String, Double> averageSalaryByDept = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.averagingDouble(Employee::getSalary)));

        // 5. Sort employees by name
        List<Employee> sortedByName = employees.stream()
                .sorted(Comparator.comparing(Employee::getName))
                .collect(Collectors.toList());

        // 6. Find the employee with the highest salary
        Optional<Employee> highestEarner = employees.stream()
                .max(Comparator.comparingDouble(Employee::getSalary));

        // 7. Find distinct departments
        Set<String> distinctDepartments = employees.stream()
                .map(Employee::getDepartment)
                .collect(Collectors.toSet());

        // 8. Collect names of all employees into a list
        List<String> employeeNames = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());

        // 9. Concatenate all employee names into a single string
        String concatenatedNames = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(", "));

        // 10. Check if any employee earns more than 75,000
        boolean anyHighEarner = employees.stream()
                .anyMatch(e -> e.getSalary() > 75000);

        // 11. Calculate total salary of all employees
        double totalSalary = employees.stream()
                .mapToDouble(Employee::getSalary)
                .sum();

        // Print all the results
        System.out.println("Employees in Engineering:");
        engineeringEmployees.forEach(System.out::println);

        System.out.println("\nEmployees earning more than 60,000:");
        highEarners.forEach(System.out::println);

        System.out.println("\nEmployees grouped by department:");
        employeesByDept.forEach((dept, empList) -> System.out.println(dept + ": " + empList));

        System.out.println("\nAverage salary by department:");
        averageSalaryByDept.forEach((dept, avgSalary) -> System.out.println(dept + ": " + avgSalary));

        System.out.println("\nEmployees sorted by name:");
        sortedByName.forEach(System.out::println);

        System.out.println("\nEmployee with the highest salary:");
        highestEarner.ifPresent(System.out::println);

        System.out.println("\nDistinct departments:");
        distinctDepartments.forEach(System.out::println);

        System.out.println("\nList of employee names:");
        System.out.println(employeeNames);

        System.out.println("\nConcatenated employee names:");
        System.out.println(concatenatedNames);

        System.out.println("\nAny employee earning more than 75,000?");
        System.out.println(anyHighEarner);

        System.out.println("\nTotal salary of all employees:");
        System.out.println(totalSalary);
    }
}

Output:

Employees in Engineering:
Employee{id=2, name='Bob', department='Engineering', salary=70000.0}
Employee{id=3, name='Charlie', department='Engineering', salary=80000.0}

Employees earning more than 60,000:
Employee{id=3, name='Charlie', department='Engineering', salary=80000.0}
Employee{id=2, name='Bob', department='Engineering', salary=70000.0}

Employees grouped by department:
HR: [Employee{id=1, name='Alice', department='HR', salary=45000.0}, Employee{id=4, name='David', department='HR', salary=50000.0}]
Engineering: [Employee{id=2, name='Bob', department='Engineering', salary=70000.0}, Employee{id=3, name='Charlie', department='Engineering', salary=80000.0}]
Finance: [Employee{id=5, name='Eve', department='Finance', salary=60000.0}, Employee{id=6, name='Frank', department='Finance', salary=55000.0}]

Average salary by department:
HR: 47500.0
Engineering: 75000.0
Finance: 57500.0

Employees sorted by name:
Employee{id=1, name='Alice', department='HR', salary=45000.0}
Employee{id=2, name='Bob', department='Engineering', salary=70000.0}
Employee{id=3, name='Charlie', department='Engineering', salary=80000.0}
Employee{id=4, name='David', department='HR', salary=50000.0}
Employee{id=5, name='Eve', department='Finance', salary=60000.0}
Employee{id=6, name='Frank', department='Finance', salary=55000.0}

Employee with the highest salary:
Employee{id=3, name='Charlie', department='Engineering', salary=80000.0}

Distinct departments:
HR
Engineering
Finance

List of employee names:
[Alice, Bob, Charlie, David, Eve, Frank]

Concatenated employee names:
Alice, Bob, Charlie, David, Eve, Frank

Any employee earning more than 75,000?
true

Total salary of all employees:
350000.0

Explanation of Key Methods

  1. Filter:

    • Filters elements based on a predicate.
    stream.filter(e -> e.getDepartment().equals("Engineering"))
  1. Map:

    • Transforms elements in the stream.
    stream.map(Employee::getName)
  1. Collect:

    • Gathers elements into a collection, map, or concatenated string.
    stream.collect(Collectors.toList());
  1. Grouping By:

    • Groups elements by a classifier function.
    stream.collect(Collectors.groupingBy(Employee::getDepartment));
  1. Sorting:

    • Sorts elements based on a comparator.
    stream.sorted(Comparator.comparing(Employee::getName))
  1. Reducing:

    • Performs a reduction operation like finding the max or sum.
    stream.max(Comparator.comparingDouble(Employee::getSalary))
  1. Terminal Operations:

    • Operations like forEach, collect, findFirst, and reduce end the stream pipeline.