Consumer interface in Java

The Consumer interface was introduced in Java 1.8. Below is a an excerpt from the official documentation

Represents an operation that accepts a single input argument and returns no result. Unlike most other functional interfaces, Consumer is expected to operate via side-effects.

I want to talk about the Consumer functional interface in this article because I find it very useful and use it often.

Consumer definition

Consumer is an interface with as single abstract method accept(T t).

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

The accept method, as its name suggests, "consumes" a value and performs a specific operation on it.

Uses of Consumer interface

  1. The behavior (accept method) of the consumer interface is well known. As a result, it increases the readability of the code.
  2. Enhances code reusability by leveraging pre-existing interfaces rather than creating custom ones for the same behavior.
  3. As it is a functional interface, it can be efficiently defined using lambda expressions.
  4. The Consumer interface is commonly utilized in many new Java methods, such as those found in the Stream class.
  5. The Consumer instances can be executed sequentially by utilizing the andThen method.

Example of Consumer interface

Let us view some examples of Consumer interface. To gauge its usability, we will first try to solve the problem without Consumer interface.

Problem Statement Let us consider a class PerformLongOperation which is doing some complex operation and keeps posting progress of its update to the listener. The listener needs to be passed as a parameter of doTask function which perform the actual task.

Solution 1: Using interface Here, we will use IOnTaskUpdateCallback interface to define the callback contract. Below will be one solution

class HelloWorld {
    static class PerformLongOperation {
        public void doTask(IOnTaskUpdateCallback onTaskUpdatedCallback) {
            onTaskUpdatedCallback.onProgressUpdated(0);
            for (int i = 10; i <= 100; i+=10) {
                try {
                    // add sleep to show task is being done
                    Thread.sleep(1000);
                } catch (InterruptedException exp) {
                    // ignoring for now
                }
                onTaskUpdatedCallback.onProgressUpdated(i);
            }
        }
    }

    interface IOnTaskUpdateCallback {
        // called when any update in the progress
        void onProgressUpdated(int progress);
    }

    public static void main(String[] args) {
        PerformLongOperation longGoing = new PerformLongOperation();
        longGoing.doTask(new IOnTaskUpdateCallback() {
            @Override
            public void onProgressUpdated(int progress) {
                System.out.println("Progress is: " + progress);
            }
        });
    }
}

Solution 1.1: Using interface and lambda We can make our main() method more concise by using lambda like below

public static void main(String[] args) {
    PerformLongOperation longGoing = new PerformLongOperation();
    longGoing.doTask(progress -> System.out.println("Progress is: " + progress));
}

Solution 2: Using Consumer Since, IOnTaskUpdateCallback satisfies all condition for being a Consumer, we can just use Consumer rather than defining a new one new interface.

class HelloWorld {
    static class PerformLongOperation {
        public void doTask(Consumer<Integer> onTaskUpdatedCallback) {
            onTaskUpdatedCallback.accept(0);
            for (int i = 10; i <= 100; i+=10) {
                try {
                    // add sleep to show task is being done
                    Thread.sleep(1000);
                } catch (InterruptedException exp) {
                    // ignoring for now
                }
                onTaskUpdatedCallback.accept(i);
            }
        }
    }

    public static void main(String[] args) {
        PerformLongOperation longGoing = new PerformLongOperation();
        longGoing.doTask(progress -> System.out.println("Progress is: " + progress));
    }
}

To sum up, the Consumer functional interface in Java simplifies coding, enhances reusability, and streamlines development, making it a valuable tool for efficient programming.

0
Subscribe to my newsletter

Read articles from Sajal Raj Gautam directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sajal Raj Gautam
Sajal Raj Gautam

I’m a software engineer with a focus on Android applications and framework development. I specialize in tackling complex challenges with innovative solutions. I’ve worked across various form factors and software layers, contributing to the various software development lifecycle—design, development, testing, planning, and performance optimization. Leading teams, I ensure quality deliverables within deadlines. Beyond Android, I’ve gained hands-on experience in Robotics, IoT devices, RTOS applications, and Machine Learning. My dynamic career journey reflects my enthusiasm for learning and adapting to new technologies. I’m eager to explore opportunities and contribute to cutting-edge developments in the tech industry.