Introduction
I will discuss here about the new feature added to Java 8 – a functional interface, Supplier
, Consumer
and BiConsumer
. In simple words, a supplier is a method that returns a value. A supplier is any method which takes no arguments and returns a value. Its job is to supply an instance of an expected class.
Whereas, a consumer is a method that consumes some value (as in method argument), and does some operations on them. So a Consumer is any method which takes arguments and returns nothing.
A consumer is invoked for its side-effects. In Java terms, a Consumer is an idiom for a void method. ‘setter’ methods are good examples of consumers.
A BiConsumer is similar to the consumer and it accepts two inputs and does not return anything.
Prerequisites
Java at least 8
Supplier
For example, every reference to a getter method is a supplier.
public class MyClass {
private Integer count;
public Integer getCount() {
return this.count;
}
}
Its instance method reference myClass::getCount
is an instance of Supplier.
Supplier is a functional interface, in Java 8 under package java.util.function
, that represents the structure and does not take any input but returns an output. This functional interface can be used as the assignment target for a lambda expression or method reference. It’s written in the following manner – Java source documentation:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
The purpose of this in-built functional interface, Supplier, is to provide a ready-made template for functional interface having common function descriptor (functional method signature/definition).
The functional interfaces defined under package java.util.function
do not have semantics and they merely represent the structure of a function that returns a value or takes number of arguments.
The Supplier
interface also have a method T get()
that returns a value of of type T
.
A supplier is a way to create instance of a method that returns something or in other words its job is literally to supply an instance of an expected class.
Supplier functional interface doesn’t take any input but returns an output. Therefore whenever you need a function that returns something, for example, an Integer
, but takes no output, this is an instance of Supplier
.
Examples for Supplier functional interface using lambda expression can be given as shown below:
Supplier<Integer> supplierInteger = () -> 50;
System.out.println(supplierInteger.get());
Supplier<String> supplierString = () -> "Soumitra";
System.out.println(supplierString.get());
You can have a look at examples on how to use supplier:
- REST over Https with Client certificate Authentication
- Event Driven Streaming using Spring Cloud Stream and Apache Kafka
Consumer
For example, every reference to a setter method is consumer:
public class MyClass {
private Integer count;
public void setCount(Integer count){
this.count = count;
}
}
Its instance method reference myClass::setCount
is an instance of consumer.
So, if you want to input an Integer and do something with it with no output, then instead of defining your own interface use an instance of Consumer.
Consumer functional interface in Java 8 under package java.util.function
represents the structure and takes input but does not return any output. This functional interface can be used as the assignment target for a lambda expression or method reference. It’s written in the following manner – Java source documentation:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after);
}
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. This is a functional interface whose functional method is accept(Object)
.
The default method returns a composed Consumer that performs, in sequence, this operation followed by the after operation. If performing either operation throws an exception, it is relayed to the caller of the composed operation. If performing this operation throws an exception, the after operation will not be performed.
Example of side effect in the Consumer:
User user = new User("Soumitra");
Consumer<User> updateName = u -> u.setName("Roytuts");
updateName.accept(user);
System.out.println(user.getName()); //Roytuts
In the above code snippets, notice that the name of the user has been changed later. This is a side effect of the Consumer functional interface.
BiConsumer
BiConsumer is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. It represents an operation that accepts two input arguments and returns no result. This is the two-arity specialization of Consumer. Unlike most other functional interfaces, BiConsumer is expected to operate via side-effects.
This is a functional interface whose functional method is accept(Object, Object)
.
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
default BiConsumer<T,U> andThen(BiConsumer<? super T,? super U> after)
}
Type Parameters:
T – the type of the first argument to the operation
U – the type of the second argument to the operation
Example of BiConsumer can be given as:
BiConsumer<String, String> bc = (x, y) -> {
System.out.println(x + y);
};
bc.accept("1", "2");
The example using method reference can be given as:
BiConsumer<User, String> urbc = BiConsumerExample::showDetails;
urbc.accept(new User("Liton"), "32");
You can download the whole source code later from the Source Code section.
Examples – Supplier, Consumer and BiConsumer
Supplier
In this example, the Supplier is supplying string value.
package com.roytuts.java.supplier.consumer;
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
supply(() -> "Hi");
supply(() -> "Hey");
supply(() -> "Hello");
Supplier<Integer> supplierInteger = () -> 50;
System.out.println(supplierInteger.get());
Supplier<String> supplierString = () -> "Soumitra";
System.out.println(supplierString.get());
}
public static void supply(Supplier<?> supplier) {
System.out.println(supplier.get());
}
}
Running the above program you will see the following output:
Hi
Hey
Hello
50
Soumitra
Consumer
The Consumer consumes string value in the following example.
package com.roytuts.java.supplier.consumer;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
List<String> greets = Arrays.asList("Hi", "Hey", "Hello");
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
greets.forEach(consumer);
System.out.println("===============================");
User user = new User("Soumitra");
Consumer<User> updateName = u -> u.setName("Roytuts");
updateName.accept(user);
System.out.println(user.getName());
}
}
Executing the above program will give you the following output:
Hi
Hey
Hello
===============================
Roytuts
BiConsumer
Using lambda and method reference the example for BiConsumer functional interface can be written as:
package com.roytuts.java.supplier.consumer;
import java.util.function.BiConsumer;
public class BiConsumerExample {
public static void main(String[] args) {
BiConsumer<String, String> bc = (x, y) -> {
System.out.println(x + y);
};
bc.accept("1", "2");
System.out.println("=========================");
// Using lambda expression
BiConsumer<User, String> ubc = (user, age) -> {
System.out.println(user.getName() + " -> " + age);
};
ubc.accept(new User("Rahul"), "35");
// Using method reference
BiConsumer<User, String> urbc = BiConsumerExample::showDetails;
urbc.accept(new User("Liton"), "32");
}
private static void showDetails(User user, String age) {
System.out.println(user.getName() + " -> " + age);
}
}
Running the above program will give you the following output:
12
=========================
Rahul -> 35
Liton -> 32
That’s all about Supplier, Consumer and BiConsumer examples.