Java8:Effective use of Consumer Functional Interface

Java8 provides a functional interface called Consumer, Whose signature looks like following

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
       Objects.requireNonNull(after);
       return (T t) -> { accept(t); after.accept(t); };
    }
}

So, consumer has one default method andThen and one abstract method accept. I will discuss  the andThen later, let's concentrate on accept method.

Seeing the signature of accept, one thing is clear it takes an argument and produce nothing so it returns type is void. So the consumer is logically opposite of Supplier-- which takes nothing but produce something. I can say Produces can start a flow and Consumer ends that flow, Consumer acts as a terminal operation which can complete a method chain.

By use of method reference feature in java8, we can reference any method whose signature matches the accept method of Consumer so we can refer that method as a consumer functional interface.

Let see a simple example where I want to create and display the mail (Don’t do this in production it breaks SRP, create and display should be two separate methods  It is just for example purpose).

Very basic code will look like following

package com.example.consumer;

import java.io.StringWriter;
import java.util.function.Consumer;

public class EmailManager {
   
   public void createAndDisplayEmail(String emailBody){
      StringWriter writer = new StringWriter();
      writer.append("Hi,");
      writer.append("\n");
      writer.append(emailBody);
      writer.append("\n");
      writer.append("Thanks, Shamik");
      System.out.println(writer.toString());
     
   }
   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      manager.createAndDisplayEmail("This is a mail from Javaonfly");
   }

}



Output :
Hi
This is a mail from Javaonfly
Thanks, Shamik


Nothing fancy, The createAndDisplayEmail method takes the body content then add salutation and footer to the body after that it prints the email.

As the method signature of the createAndDisplayEmail match with Consumer’s accept method signature, we can use java8 method reference and hold the reference of the createAndDisplayEmail in Consumer functional interface so we can invoke the method later when required, to achieve that we just we need to add following code snippet in the main method.


Consumer<String> consumer = manager::createAndDisplayEmail;
consumer.accept("This is a mail from Javaonfly");

After seeing the above code an inquisitive mind immediately ask two questions
1. What is the benefit of holding the reference in Consumer functional interface,
2. How that is differ from the call manager.createAndDisplayEmail("This is a mail from Javaonfly") apart from syntax.


There are several benefits by doing that, first, let me answer  the second question
How that differs from the call manager.createAndDisplayEmail("This is a mail from Javaonfly") apart from syntax?

prior to Java8, we don’t have privilege to treat method as variable so we can’t pass a method into another method as an argument like we usually do in case of variable, to achieve the same we have to pass an Object which holds that method, so to reuse the method either we have to make it static or has to pass the Object . Which is OK but it has a problem unnecessary we have to carry the context(i.e Object) while we need only the method definition. In Java 8 now we can easily hold the method reference using appropriate interface without context, and reuse the method later.

Now come to the first question,
What is the benefit of holding the reference in Consumer functional interface?

Consumer as a Strategy Pattern:

As we can hold the reference of a method in Consumer Functional interface and Consumer is an interface so we can have multiple implementations--- the question is, what are those implementation then, as Consumer holds method reference we can say it holds any methods whose method signature is matched with Consumer, and they can act as Strategy-- based on the context we can pass different method reference in to higher-order method.  so lower level methods act as an implementation of the strategy.

Hard to digest? let understand it through our Mail example

Suppose, Now we have to add new functionality into our EmaiManager class, Requirements is like that, as Javaonfly company has several departments When we send the mail that should have department specific formats and in the footer section we have to change the signature based on department.

So it is obvious the salutation, footer, the format will be changed dynamically based on the department, How we can implement the same.

Prior to Java 8, we will create an interface which has footer, salutation and format method and based on department we will implement several classes based on the department, and in EmaiManager class in createandDisplay method, we will pass the interface and email body as arguments and based on department we will pass actual implementation.

So, we need to create multiple classes, But same can be achieved very short and crisply way using Consumer interface. The Consumer is a predefined interface and can hold methods reference we will create various overloaded/separate methods based on department and then create a Higher-order function which takes Consumer interface and email body, then apply the consumer upon email body.

Let see the code

package com.example.consumer;

import java.io.StringWriter;
import java.util.function.Consumer;

public class EmailManager {
   
   
   
   public void createAnddisplayEmail(String emailBody){
      StringWriter writer = new StringWriter();
      writer.append("Hi,");
      writer.append("\n");
      writer.append(emailBody);
      writer.append("\n");
      writer.append("Thanks, Shamik");
      System.out.println(writer.toString());
     
   }
   
   public void createAnddisplayAdminEmail(String emailBody){
      StringWriter writer = new StringWriter();
      writer.append("Hi,");
      writer.append("\n");
      writer.append(emailBody);
      writer.append("\n");
      writer.append("Thanks, Admin");
      System.out.println(writer.toString());
     
   }
   
   public void createMailandDisplay(Consumer<String> consumer,String mailBody){
      consumer.accept(mailBody);
   }
   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      String body ="This is a mail from Javaonfly";
      Consumer<String> directorEmailConsumer = manager::createAnddisplayEmail;
      Consumer<String> adminEmailConsumer = manager::createAnddisplayAdminEmail;
      manager.createMailandDisplay(directorEmailConsumer, body);
      manager.createMailandDisplay(adminEmailConsumer, body);
     
   }

}

If you look at the code minutely you will find there is a higher order function called createMailandDisplay which takes mail body and consumer which act as Higher order class in the Strategy pattern and the methods createAndDisplayEmail and createAnddisplayAdminEmail are the actual implementation of the strategy which were pass from main method.

Consumer as a Filter Chain Pattern :
As Consumer takes one input and produce nothing, so it behaves like a terminal operation, but sometimes we need to apply series of actions on the input.  Generally in OO design we do it through FilterChain where we will create an interface with a method doFilter() then implements multiple classes based on the action which we apply on the input, also create a FilteManger class which iterate over the filters and apply the filter on input, or a filter apply itself then delegate the call to next filter. The Same concept can be achieved through Consumer interface where each filter implementation represents a method and a Higher-order function treat as Filter manager which will iterate over methods and apply it to the input.

Let try to solve a problem using Filter pattern,

Suppose before creating and sending any mail we want to apply spell checking, grammar checking and format checking on the email body, so that email body is error-free and well formatted. How we can achieve the same using consumer.

Obvious there is a series of actions spell check, grammar check will be applied to email body so we can use Filter pattern there.

Let see the code

package com.example.consumer;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;


public class EmailManager {
   
   public void spellChecker(String emailBody){
      System.out.println("Spell Checking on :: " + emailBody);
     
   }
   public void grammarChecker(String emailBody){
      System.out.println("Grammar Checking on :: " + emailBody);
     
   }
   public void formatChecker(String emailBody){
      System.out.println("Format Checking on :: " + emailBody);
     
   }
   
   public void applyFilter(List<Consumer<String>> filterList,String emailBody){
      filterList.forEach(filter->filter.accept(emailBody));
   }
   
   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      String body ="This is a mail from Javaonfly";
      List<Consumer<String>> filterList=new ArrayList<Consumer<String>>();
      filterList.add(manager::spellChecker);
      filterList.add(manager::grammarChecker);
      filterList.add(manager::formatChecker);
      manager.applyFilter(filterList, body);
     
   }

}



Ouput ::
Spell Cheking on :: This is a mail from Javaonfly
Grammar Cheking on :: This is a mail from Javaonfly
Format Cheking on :: This is a mail from Javaonfly


Here, I have to create a List and add the specific consumer which act as a filter, alternatively, I can use andThen functionality of the Consumer, Which takes another consumer as an input then returns a consumer which apply the consumer creates it then apply the consumer which passed as an argument. We can use this functionality which is same as filter chain.

Lets look more sophisticated version,



package com.example.consumer;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class EmailManager {
   
   public void spellChecker(String emailBody){
      System.out.println("Spell Cheking on :: " + emailBody);
     
   }
   public void grammarChecker(String emailBody){
      System.out.println("Grammar Cheking on :: " + emailBody);
     
   }
   public void formatChecker(String emailBody){
      System.out.println("Format Cheking on :: " + emailBody);
     
   }
   

   public void applyFilter(Consumer<String> composeFilter,String emailBody){
      composeFilter.accept(emailBody);
   }

   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      String body ="This is a mail from Javaonfly";
      Consumer<String> filter = manager::spellChecker;
      Consumer<String> composeFilter = filter.andThen(manager::grammarChecker).andThen(manager::formatChecker);
      manager.applyFilter(composeFilter, body);
     
   }

}




Conclusion : Consumer has multiple utilities you can use it for crisp coding and use of Method reference along with java8 defined interface we can rewrite our OOPs design pattern in a shorter and crisp way , but as now behaviour stuffed in methods, Its breaks the SRP, because all the methods now in one class and class has many reason to change.

Java8: deep dive to Supplier Interface



In this tutorial, we will learn How we can use a method reference as a Supplier and what we can do using this Supplier interface.


Supplier: To put it simply we use the term  Supplier when it produces something. So in terms of java Supplier is such an interface which takes no argument and produce a data type. This Data type can be any type <T>.

Java 8 create a concept called Functional Interface, Which is nothing but a Simple interface with one and only one abstract method.

Java 8 offers some inbuilt Functional Interfaces. The supplier is one of the inbuilt Functional interfaces which has only one abstract method called T get().

Please note that any interface(Custom) which has only one abstract method treated as a Functional interface in Java 8.


Let see the  Supplier Functional Interface in Java 8.

@FunctionalInterface
public interface Supplier<T> {

    /**
    * Gets a result.
    *
    * @return a result
    */
    T get();
}

So, Supplier is an Interface which takes no argument and returns any type (T) when invoked the get() function.

So we can say it is a kind of no args Lambda, which produces some type of value, This value can be a single value or collection of values depends on the implementation of lambda.

Now we will discuss how we can use Supplier in our program.

Constructor As a Supplier


One of the great features of Java 8 is method reference, we will talk about it in a later article but for now, By method reference, we can assign any method whose method signature match with any functional interface. Java 8 infer the type of functional interface when we pass method reference as a parameter or assign it to a functional interface.
We can use :: to use method reference instead of calling the same by . operator.

When I say by :: you can refer any method, I mean by it, it includes constructor also.
If we pay attention to the constructor which produces a class instance and takes nothing.
So it has the same signature as Supplier.



Let take a look How we can use Constructor as a supplier.

package com.example.supplier;

import java.util.ArrayList;
import java.util.function.Supplier;

public class LambdaASSupplier {
   
   Supplier<ArrayList> arryListSupplier = ArrayList::new;
   
   ArrayList produceArrayList(){
      return arryListSupplier.get();
   }
   
   

}


Here,  we refer the constructor using a method reference, so it returns a functional interface whose signature is same as Supplier, So we can reference the constructor using Supplier interface. By doing this we defer the ArrayList Object creation,  by new ArrayList() call we create an ArrayList Object instantly but using method reference we wrap constructor into an interface and execute the logic i.e create ArrayList when we call get method in the produceArrayList method.

Now we will try to make it generic,  we will try to create a method which will take any type of supplier and return specific type Object based on the supplier type.



package com.example.supplier;

import java.util.ArrayList;
import java.util.Date;
import java.util.function.Supplier;

public class LambdaASSupplier {
   
   public static <T> T  supplyElements(Supplier<T> supplier){
      return supplier.get();
   }
   
   public static void main(String[] args) {
      String s = LambdaASSupplier.supplyElements(String::new);
      ArrayList arraList = LambdaASSupplier.supplyElements(ArrayList::new);
      Date date = LambdaASSupplier.supplyElements(Date::new);
     
   }
   
   

}



We take Supplier<T> as an argument of supplyElements and returns T based on supplier type.

So we can say Constructor is a good candidate for supplying value, so we can refer constructor as a supplier and use the same to create Objects when the program needs it elsewher



Factory method as a Supplier :

Think about the factory method it is a static method which takes nothing but returns an Object so it is a potential candidate for Supplier interface, So we can use any factory method as a Supplier.

Let see a small example

package com.example.supplier;

public interface Shape {
   void display();

}

I have create a Shape interface which has a display method. Then I will create a Factory class which will produce different shapes.

Let see the Factory class

package com.example.supplier;

import java.util.function.Supplier;

public class ShapeFactory {
   
   public static Shape createRectangel(){
      return new Shape(){
          @Override
          public void display() {
              System.out.println(" I am a Rectangle");
             
          }
         
      };
     
   }
   
   public static Shape createSquare(){
      return new Shape(){
          @Override
          public void display() {
              System.out.println(" I am a Square");
             
          }
         
      };
     
   }
   
   public static void main(String[] args) {
      Supplier<Shape> recangleProducer = ShapeFactory::createRectangel;
      Supplier<Shape> squareProducer = ShapeFactory::createSquare;
     
      recangleProducer.get().display();
      squareProducer.get().display();
   }
   
   
   
   

}

Here I create two factory methods which will create a rectangle and Square shapes if you see the method signature of the factory method it is same as Supplier interface so easily we can reference this static factory method as a Supplier.

I did same in main method where I create two producer rectangle and square which are a supplier functional interface.

Later I create Rectangle or Square Object from that supplier.

We can also sophisticate our program , we can create a Factory of supplier


Let see that implementation

package com.example.supplier;

import java.util.function.Supplier;

public class ShapeProducerFactory {
   
   public static Supplier<Shape> createRectangleProducer()
   {
      return ShapeFactory::createRectangel;
   }
   
   public static Supplier<Shape> createsquareProducer()
   {
      return ShapeFactory::createSquare;
   }
   
   public static void main(String[] args) {
      ShapeProducerFactory.createRectangleProducer().get().display();
      ShapeProducerFactory.createsquareProducer().get().display();
   }

}

I just create a Factory of producers here which will produce the specific shape.


Conclusion: Supplier functions interface can be used as a reference of constructor, factory method so we can pass supplier interface as a  pointer of constructor or method, so we can invoke them later. In another place. So in a one-word Supplier interface give us the facility to pass producing behavior into a another method or as a variable so we can use that behavior later as a callback.