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
- The behavior (accept method) of the consumer interface is well known. As a result, it increases the readability of the code.
- Enhances code reusability by leveraging pre-existing interfaces rather than creating custom ones for the same behavior.
- As it is a functional interface, it can be efficiently defined using lambda expressions.
- The
Consumer interface is commonly utilized in many new Java methods, such as those found in the Stream class.
- 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 {
Thread.sleep(1000);
} catch (InterruptedException exp) {
}
onTaskUpdatedCallback.onProgressUpdated(i);
}
}
}
interface IOnTaskUpdateCallback {
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 {
Thread.sleep(1000);
} catch (InterruptedException exp) {
}
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.