Java 8 : Functional Interfaces

Java 8 introduced functional interfaces to support functional programming paradigms using lambdas and streams, making the code more readable and expressive. These interfaces help in handling different real-world programming scenarios such as filtering data, transforming objects, executing operations, and aggregating values efficiently.

Interface Description Example
Predicate<T>Tests a condition and returns true or false.Filtering employees with a salary above $100,000.
Function<T, R>Transforms an object of type T into R.Extracting and converting salaries from a list of employees.
Consumer<T>Accepts an object and performs an operation without returning anything.Logging or printing employee details.
Collector<T, A, R>Collects and reduces elements from a stream.Grouping employees by department or summing up salaries.
Supplier<T>Supplies an object without any input.Creating a default employee object when no data is available.
UnaryOperator<T>A Function that takes and returns the same type.Applying a 10% salary increase to all employees.
BinaryOperator<T>A Function that takes two arguments and returns the same type.Summing up salaries of employees

1. Predicate<T> – Represents a boolean-valued function of one argument

Commonly used in filtering operations (e.g., stream().filter(...)).

It tests the given input and returns true or false.

Predicate<Employee> salaryGreaterThan100Thousand = emp -> emp.getSalary().compareTo(new BigDecimal(100000)) > 0;
Predicate<Employee> idGreaterThan1 = emp -> emp.getId() > 1;

// Using Predicate in stream filter
List<Employee> highSalaryEmployees = employees.stream()
        .filter(salaryGreaterThan100Thousand.and(idGreaterThan1))
        .collect(Collectors.toList());

System.out.println(highSalaryEmployees);

2. Function<T, R> – Represents a function that takes an input T and returns a result R

Useful for transforming objects (e.g., extracting specific fields, mapping objects).

Function<Employee, Integer> getSalary = emp -> emp.getSalary().intValue();

// Example usage: Map employee list to salary list
List<Integer> salaries = employees.stream()
        .map(getSalary)
        .collect(Collectors.toList());

System.out.println(salaries);

3. Consumer<T> – Represents an operation that accepts a single input and returns no result

Used for performing actions like printing, logging, or modifying objects.

Consumer<Employee> printEmployee = emp -> System.out.println(emp.getName() + " earns " + emp.getSalary());

// Example usage: Print each employee
employees.forEach(printEmployee);

4. Collector<T, A, R> – Used for reducing and collecting elements of a stream

It helps perform operations like grouping, summing, or joining elements.

Map<String, List<Employee>> employeesByDepartment = employees.stream()
        .collect(Collectors.groupingBy(Employee::getDepartment));

System.out.println(employeesByDepartment);

5. Supplier<T> – Represents a supplier of results

It does not take any arguments but produces an object of type T when called.

Supplier<Employee> newEmployeeSupplier = () -> new Employee(0, "New Employee", new BigDecimal(50000), "HR");

// Example usage: Create a new Employee instance
Employee newEmployee = newEmployeeSupplier.get();
System.out.println(newEmployee);

6. UnaryOperator<T> – A special case of Function<T, T> where the input and output types are the same

Used for performing operations that return the same type, such as modifying values.

UnaryOperator<BigDecimal> incrementSalary = salary -> salary.multiply(BigDecimal.valueOf(1.1)); // Increases salary by 10%

// Example usage: Apply a 10% salary increment
employees.forEach(emp -> emp.setSalary(incrementSalary.apply(emp.getSalary())));

7. BinaryOperator<T> – Represents an operation on two operands of the same type, producing a result of the same type

Useful for performing calculations like summing numbers, finding min/max, etc.

BinaryOperator<BigDecimal> sumSalaries = (sal1, sal2) -> sal1.add(sal2);

// Example usage: Calculate total salary of all employees
BigDecimal totalSalary = employees.stream()
        .map(Employee::getSalary)
        .reduce(BigDecimal.ZERO, sumSalaries);

System.out.println("Total Salary: " + totalSalary);

These examples demonstrate how Java 8 functional interfaces can simplify common tasks such as filtering, transforming, aggregating, and modifying collections.

Leave a comment