Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When we should use Supplier in Java 8?

What difference between this code?

Supplier<LocalDate> s1 = LocalDate::now; LocalDate s2 = LocalDate.now();  System.out.println(s1.get()); //2016-10-25 System.out.println(s2); //2016-10-25 

I start learning functional interfaces in Java 8 and don't understand the benefit of the Supplier. When and how, exactly, should use them. Does the Supplier improve performance or maybe the benefits on abstraction level?

Thanks for your answers! And it isn't duplicate question because I used search and didn't find what I need.

UPDATE 1: You mean this?

    Supplier<Long> s1 = System::currentTimeMillis;     Long s2 = System.currentTimeMillis();      System.out.println(s1.get()); //1477411877817     System.out.println(s2); //1477411877817     try {         Thread.sleep(3000l);     } catch (InterruptedException e) {         e.printStackTrace();     }     System.out.println(s1.get()); //1477411880817 - different     System.out.println(s2); //1477411877817 
like image 991
badCoder Avatar asked Oct 25 '16 15:10

badCoder


People also ask

When should we use supplier in Java?

Java's functional supplier interface can be used any time a function needs to generate a result without any data passed into it. Now, contrast that with Java's functional Consumer interface which does the opposite. The Consumer interface will pass data, but no result will be returned to the calling program.

Why do we use supplier in Java 8?

Java 8 Supplier is a functional interface whose functional method is get(). The Supplier interface represents an operation that takes no argument and returns a result. As this is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

What is the use of supplier?

A supplier is a person or business that provides a product or service to another entity. The role of a supplier in a business is to provide high-quality products from a manufacturer at a good price to a distributor or retailer for resale.

What is a supplier T in Java?

A Supplier<T> interface is a pre-defined interface that represents the supplier of results. It is instantiated using lambda expression or method reference or default constructor. The functional method of a Supplier<T> interface is the get() method. This interface belongs to java. util.


2 Answers

I'll go through a scenario where we should use Supplier<LocalDate> instead of LocalDate.

Code that directly makes calls to static methods like LocalDate.now() is very difficult to unit test. Consider a scenario where we want to unit test a method getAge() that calculates a person's age:

class Person {     final String name;     private final LocalDate dateOfBirth;      Person(String name, LocalDate dateOfBirth) {         this.name = name;         this.dateOfBirth = dateOfBirth;     }      long getAge() {         return ChronoUnit.YEARS.between(dateOfBirth, LocalDate.now());     } } 

This works fine in production. But a unit test would either have to set the system's date to a known value or be updated every year to expect the returned age to be incremented by one, both pretty aweful solutions.

A better solution would be for the unit test to inject in a known date while still allowing the production code to use LocalDate.now(). Maybe something like this:

class Person {     final String name;     private final LocalDate dateOfBirth;     private final LocalDate currentDate;      // Used by regular production code     Person(String name, LocalDate dateOfBirth) {         this(name, dateOfBirth, LocalDate.now());     }      // Visible for test     Person(String name, LocalDate dateOfBirth, LocalDate currentDate) {         this.name = name;         this.dateOfBirth = dateOfBirth;         this.currentDate = currentDate;     }      long getAge() {         return ChronoUnit.YEARS.between(dateOfBirth, currentDate);     }  } 

Consider a scenario where the person's birthday has passed since the object was created. With this implementation, getAge() will be based on when the Person object was created rather than the current date. We can solve this by using Supplier<LocalDate>:

class Person {     final String name;     private final LocalDate dateOfBirth;     private final Supplier<LocalDate> currentDate;      // Used by regular production code     Person(String name, LocalDate dateOfBirth) {         this(name, dateOfBirth, ()-> LocalDate.now());     }      // Visible for test     Person(String name, LocalDate dateOfBirth, Supplier<LocalDate> currentDate) {         this.name = name;         this.dateOfBirth = dateOfBirth;         this.currentDate = currentDate;     }      long getAge() {         return ChronoUnit.YEARS.between(dateOfBirth, currentDate.get());     }      public static void main(String... args) throws InterruptedException {         // current date 2016-02-11         Person person = new Person("John Doe", LocalDate.parse("2010-02-12"));         printAge(person);         TimeUnit.DAYS.sleep(1);         printAge(person);     }      private static void printAge(Person person) {         System.out.println(person.name + " is " + person.getAge());     } } 

The output would correctly be:

John Doe is 5 John Doe is 6 

Our unit test can inject the "now" date like this:

@Test void testGetAge() {     Supplier<LocalDate> injectedNow = ()-> LocalDate.parse("2016-12-01");     Person person = new Person("John Doe", LocalDate.parse("2004-12-01"), injectedNow);     assertEquals(12, person.getAge()); } 
like image 151
joshden Avatar answered Sep 25 '22 14:09

joshden


It definitely doesn't improve the performance. Your question is similar to this one: Why are we using variables? We could simply just recalculate everything every time we need it. Right?

If you need to use a method a lot of times, but it has a wordy syntax.

Let's assume you have a class named MyAmazingClass, and you have a method in it with the name MyEvenBetterMethod (which is static), and you need to call it 15 times at 15 different positions in your code. Of course, you can do something like...

int myVar = MyAmazingClass.MyEvenBetterMethod(); // ... int myOtherVar = MyAmazingClass.MyEvenBetterMethod(); // And so on... 

...but you can also do

Supplier<MyAmazingClass> shorter = MyAmazingClass::MyEvenBetterMethod;  int myVar = shorter.get(); // ... int myOtherVar = shorter.get(); // And so on... 
like image 44
Bálint Avatar answered Sep 23 '22 14:09

Bálint