Search This Blog

Tuesday 25 August 2015

Suppliers in Java Lambda World

In the previous post I had a look at Consumer function objects and how they were used in the forEach method of the Iterable class. An exactly opposite kind of interface to the Consumer is the Supplier interface. (like the name doesn't give it away)
To be honest I had a tough time coming up with a use case for this.I decided to first use this in a few places.
I first created a simple class Ticket:
public class Ticket {

   private static int counter = 0;

   public Ticket() {
      counter++;
   }

   public static Ticket getSpecialTicket() {
      // some processing needed to get ticket
      counter++;
      return new Ticket();
   }

   public static int getTicketCount() {
      return counter;
   }
   
   @Override
   public String toString() {
      return "T[" + this.hashCode() +"]";
   }
}
The next step was to pass a ticket generator for use in application code. Normal way to do it would be:
public static void performOperation(){
      //get details of operation
      //generate a ticket
      Ticket ticket = new Ticket();
      //use the ticket instance to perform operation
      System.out.println("Ticket " + ticket + " used for operation");
   }
Here we see the ticket being generated and used in code. If we had different sub-classes of tickets than we need to place that logic within the peformOperation method or else pass the ticket as a parameter. But what if we need multiple tickets ?
A more suitable way would be to move this logic into a different abstraction and pass this as a parameter to the performOperation method.
The Supplier interface could be an easy way to achieve this without having to write any code.
public static void performOperation(Supplier<? extends Ticket> ticketSupplier) {
      // get details of operation
      // generate a ticket
      Ticket ticket1 = ticketSupplier.get();
      // use the ticket instance to perform operation
      System.out.println("Ticket " + ticket1 + " used for operation");
      //using the second ticket for 
      Ticket ticket2 = ticketSupplier.get();
      // use the ticket instance to perform operation
      System.out.println("Ticket " + ticket2 + " used for operation");
   }
As can be seen here an instance of Supplier is passed here. Every time a ticket is needed, a call to the get method of Supplier class is made. As per the java documentation:
Represents a supplier of results. 
There is no requirement that a new or distinct result be returned each time the supplier is invoked. 
This is a functional interface whose functional method is get().
The client code for execution would be:
public static void main(String[] args) {
      performOperation(Ticket::new);
   }
As can be seen here, the code makes two calls to get instance of Supplier - this will result in tow calls to Ticket constructor, which will return us two ticket objects. If I wanted the static method to be used here:
public static void main(String[] args) {
//      performOperation(Ticket::new);
       performOperation(Ticket::getSpecialTicket);
   }
In both the cases every call to get will return a new ticket instance.
Ticket T[617901222] used for operation
Ticket T[1159190947] used for operation
However if a singleton type of method was passed to Supplier, than we would have a single value returned by all calls to get. In both of the above calls, I used method reference. We can also achieve the same using lambda expressions:
performOperation(()->new Ticket());
performOperation(()-> getSpecialTicket());

No comments:

Post a Comment