Java 8 Consumer and Supplier

In this article we will cover Java 8 Consumer and Supplier interfaces.

Introduction

The Consumer and Supplier interfaces are a couple of Functional Interfaces that belong to the new Java 8 java.util.function package. As the package name states, these interfaces are meant to be used together with the new functional Java 8 features. A complete list of the package interfaces and their descriptions may be found here: java.util.function (Java Platform SE 8).

Supplier

Suppliers represent a function that accepts no arguments and produce a result of some arbitrary type. Suppliers may reference constructor methods: Supplier referencing a constructor method Supplier<User> userSupplier = User::new; User user = userSupplier.get(); Suppliers may also reference static methods: Supplier referencing a static method Supplier<User> userSupplier = UserFactory::produceUser; User user = userSupplier.get(); class UserFactory { public static User produceUser() { return new User(); } } Instance methods are also available to be referenced by suppliers: Supplier referencing an instance method Supplier<User> userSupplier = this::produceUser; User user = userSupplier.get(); private User produceUser(){ return new User(); }

Consumer

Consumers represent a function that accepts a single argument of an arbitrary type and produce no result: Simple consumer Consumer<User> userConsumer = (u) -> System.out.println("Username: " + u.getUsername()); userConsumer.accept(user); Consumers may also be applied to streams of data in order to execute some given action against every stream element: Consumer applied to a stream List<User> userList = ...; userList.stream().forEach((u) -> System.out.println("Username: " + u.getUsername())); Streams will be covered in a later article.

Asynchronous processing

Even though Java 8 Consumers and Suppliers were included in order to supply functional features, they may remind us of the typical Publisher-Subscriber asynchronous processing architecture. Java already provides a complete infrastructure in order to implement asynchronous processing, but one could also craft something like the following using Consumers and Suppliers (even if it is just for curiosity): SupplierConsumer.java public class SupplierConsumer<T> extends Thread { private Supplier<T> supplier; private Consumer<T> consumer; private boolean shouldRun = true; public SupplierConsumer(Supplier<T> supplier, Consumer<T> consumer) { this.supplier = supplier; this.consumer = consumer; } @Override public void run() { while (shouldRun) { T item = supplier.get(); consumer.accept(item); } } } Example usage BlockingQueue<User> usersQueue = new LinkedBlockingQueue<User>(); Supplier<User> userSupplier = new Supplier<User>() { @Override public User get() { try { return usersQueue.take(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }; Consumer<User> userConsumer = new Consumer<User>() { @Override public void accept(User user) { System.out.println("Processing user " + user.getUserId()); } }; new SupplierConsumer<>(userSupplier, userConsumer).start(); for (int i = 0; i < 100; i++) { usersQueue.put(new User(i, "user" + 1)); } We use a LinkedBlockingQueue as the underlying data structure that holds the items to be processed since it is already synchronized internally. The Supplier is responsible for taking items from the queue and the Consumer is responsible for process those items. We left the SupplierConsumer class generic enough so it's just a matter of defining how the Supplier will fetch data that will be later passed to the consumer for processing.

Related Articles

Comments