Consumer Interface

The Consumer interface in Java is a functional interface representing an operation that takes a single input argument and returns no result. It is part of the java.util.function package and is useful in contexts where you want to define operations to be performed on objects, especially within collections.

Basic Syntax

Here’s how the Consumer interface is defined:

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        // implementation
    }
}

The primary method accept(T t) performs an operation on the given argument, and the andThen method allows chaining of Consumer instances.

Example Usage with Lambda Expressions

Basic Example

Here’s a basic example using a Consumer with a lambda expression to print a string:

import java.util.function.Consumer;

public class ConsumerExample {
    public static void main(String[] args) {
        Consumer<String> print = (s) -> System.out.println(s);
        print.accept("Hello, World!");  // Outputs: Hello, World!
    }
}

In this example, the lambda expression (s) -> System.out.println(s) implements the Consumer interface by printing the provided string.

Using Consumer with Collections

Consumers are particularly useful when processing collections. The forEach method in the Collection interface accepts a Consumer to apply an operation to each element in the collection.

Example: Iterating Over a List

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ListIterationExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("John", "Jane", "Jack");

        Consumer<String> printName = (name) -> System.out.println(name);
        names.forEach(printName);
    }
}

This example demonstrates using a Consumer to print each name in a list. The forEach method applies the printName consumer to each element.

Chaining Consumers

The Consumer interface’s andThen method allows chaining multiple consumers to execute sequentially.

Example: Chaining Consumers

import java.util.function.Consumer;

public class ChainingExample {
    public static void main(String[] args) {
        Consumer<String> printUpperCase = (s) -> System.out.println(s.toUpperCase());
        Consumer<String> printLowerCase = (s) -> System.out.println(s.toLowerCase());

        Consumer<String> printBoth = printUpperCase.andThen(printLowerCase);
        printBoth.accept("Hello, World!");

        // Outputs:
        // HELLO, WORLD!
        // hello, world!
    }
}

In this example, printUpperCase and printLowerCase are chained together using andThen. When printBoth.accept("Hello, World!") is called, it prints the string in both uppercase and lowercase.

Real-World Scenario

Consider a scenario where you have a list of orders, and you want to print the details of each order and then mark it as processed.

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

class Order {
    private String orderId;
    private boolean processed;

    public Order(String orderId) {
        this.orderId = orderId;
        this.processed = false;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setProcessed(boolean processed) {
        this.processed = processed;
    }

    @Override
    public String toString() {
        return "Order{orderId='" + orderId + "', processed=" + processed + "}";
    }
}

public class OrderProcessingExample {
    public static void main(String[] args) {
        List<Order> orders = Arrays.asList(
            new Order("1001"),
            new Order("1002"),
            new Order("1003")
        );

        Consumer<Order> printOrder = (order) -> System.out.println(order);
        Consumer<Order> markAsProcessed = (order) -> order.setProcessed(true);

        Consumer<Order> processOrder = printOrder.andThen(markAsProcessed);
        orders.forEach(processOrder);

        System.out.println("After processing:");
        orders.forEach(printOrder);
    }
}

In this scenario, the Order class represents an order with an ID and processed status. The printOrder consumer prints the order details, and the markAsProcessed consumer marks the order as processed. By chaining these consumers using andThen, you can process each order by first printing its details and then marking it as processed. The final list of orders is printed again to show their updated status.

By using the Consumer interface and lambda expressions, you can create clean and concise operations that are easy to read and maintain, especially when working with collections and performing sequential operations.