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.

Java8:Deep dive to Lambda as a Closure

In Java8 the most important inclusion is the lambda, It is important because  using lambda we can manipulate function/method like data member , also we can pass or returns a function from another function(using java Functional interface). Prior to java8, we can do it by anonymous class but it has a very complex signature.

Now the questions are
what is closure?
How does lambda serve as a closure?
java 8 follows pure closure?
How is Closure useful?

We are going to discuss it one by one.

what is closure?

In a very simple term closure is a function/behavior which uses a variable which is defined out of the scope of this function(method in Java).

This is very common case,

Ex:

public class Greet{
String greet =”Hello”;
public String doGreet(String name){
return greet + name;
}

}

Here, greet is a variable which declared outside of the function scope and we use it in doGreet() function. But the problem arises when a function uses or manipulate an external variable inside a closing function and returns the closing function as a return value.
Hard to understand, let think in this way,  in Java 8 we can pass or returns a function by help of the functional interface, so we can say,  like the value we can also return a function which uses an external variable.

Let's modify the code a bit using Java 8 lambda

package com.example.closure;

import java.util.function.Supplier;

public class Greet {
   
   public Supplier<String>doGreet(String name){
      String salutation = "Hello";
      return () ->salutation + " "+ name;    
             
   }
   
   public static void main(String[] args) {
      Greet greet = new Greet();
      Supplier<String> supplier = greet.doGreet("Shamik");
      String message = supplier.get();
      System.out.println(message);
     
   }

}

How does lambda serve as a closure?

Here, I just modify the code little bit, previously doGreet() directly returns a value by concatenating the name and salutation, Here I return a Functional Interface from doGreet() called Supplier(Java8 built-in functional interface) which takes nothing but produces a String, By doing this I can use that intermediate function, later on.

Here Salutation variable is declared inside doGreet() method but salutation variable used in the intermediate function Supplier<String>, so the state of the salutation variable bound into the intermediate function which is used later when we call supplier.get(). So the state of a variable
Which is defined outside the function is closed by the function or encapsulated by the function, hence the name is closure, Close the state of a foreign variable inside a function.

The closure is a function which wraps a state of a variable which is defined outside of the function and can manipulate the state.


java 8 follows pure closure?

In our example Supplier, the functional interface acts as a closure as it encapsulates the salutation variable which is defined outside of the intermediate function.

But as per the closure definition, we can manipulate the state of the external variable so let's try to modify the salutation variable inside the function.

package com.example.closure;

import java.util.function.Supplier;

public class Greet {
   
   public Supplier<String>doGreet(String name){
      String salutation = "Hello";
      return () ->
      {
          salutation = "welcome";//modifying the state
          return salutation + " "+ name;    
      };
             
   }
   
   public static void main(String[] args) {
      Greet greet = new Greet();
      Supplier<String> supplier = greet.doGreet("Shamik");
      String message = supplier.get();
      System.out.println(message);
     
   }

}


If we try to compile the above code we got a compilation error, the error says
“Local variable salutation defined in an enclosing scope must be final or effectively final”

What it tries to say is -- as salutation defined in doGreet() method, so the scope  of salutation live as long as the doGreet() method executes  by main thread, as the variable creates in stack memory. But here we use  the salutation variable inside the intermediate function Supplier<String>, we can only do this in Java if and only if we guarantee that the value of the salutation is never changed , so by the final modifier we can provide this guarantee  in java8 whether you declare final explicitly or not if you use the variable which is defined outside and use the same in lambda , java8 treats that variable as effective final, whose reference never changed.


But here we try to modify the value inside the intermediate function by assigning the value “welcome”  so the compiler complains the above.


But as per closure definition, we can manipulate the same so Java8 does not act as a pure closure but we can use the value defined outside of the function scope without modifying it which is also very useful, although Java lambda is not a pure closure but it serves most of the closure functionality very well.




How Closure is useful ?

As closure encapsulate a state of variable, so we can apply the state elsewhere in the code which brings a great dynamicity into the code, By closure, we can wrap a behavior and local state together and apply the same as a callback, so we create our own strategy and inject the same into the framework. It is the implementation of Strategy pattern in Functional programming.


Conclusion :Although in Java we have Closure in form of anonymous class previously, java 8 add some syntactic sugar to it. But in spite of that, lambda is very easy to use and we can implement some of the functional style library function, curry function. Which is very tedious to implement using an anonymous class.