When should we use the Provider in Java 8?

What is the 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 am starting to learn functional interfaces in Java 8 and don’t understand what benefits the Provider provides. When and how exactly, we must use it. Does the supplier increase productivity, or perhaps the benefits of the level of abstraction?

Thank you for your responses! And this is not a duplicate question, because I used the search and did not find what I need.

UPDATE 1: Do 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 
+5
source share
3 answers

This definitely does not improve performance. Your question is similar to this: why do we use variables? We could just simply recount everything every time we need it. Right?

If you need to use the method many times, but it has verbose syntax.

Suppose you have a class called MyAmazingClass , and you have a method in it called MyEvenBetterMethod (which is static), and you need to call it 15 times at 15 different positions of 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... 
+3
source

You are misleading functional interfaces and method references. Supplier is just a Callable like interface that you should know since Java 5, the only difference is that Callable.call allowed to throw marked Exception s, unlike Supplier.get . Thus, these interfaces will have similar use cases.

Now this interface is also a functional interface, which means that they can be implemented as a reference to a method, pointing to an existing method that will be called when the interface method is called.

So, before Java 8, you had to write

 Future<Double> f=executorService.submit(new Callable<Double>() { public Double call() throws Exception { return calculatePI(); } }); /* do some other work */ Double result=f.get(); 

and now you can write

 Future<Double> f=executorService.submit(() -> calculatePI()); /* do some other work */ Double result=f.get(); 

or

 Future<Double> f=executorService.submit(MyClass::calculatePI); /* do some other work */ Double result=f.get(); 

The question of when to use Callable has not changed at all.

Similarly, the question of when to use Supplier does not depend on how you implement it, but which API you use, i.e.

 CompletableFuture<Double> f=CompletableFuture.supplyAsync(MyClass::calculatePI); /* do some other work */ Double result=f.join();// unlike Future.get, no checked exception to handle... 
+7
source

I will consider a scenario in which we should use Supplier<LocalDate> instead of LocalDate .

Code that directly calls calls to static methods like LocalDate.now() is very difficult for unit test. Consider a scenario in which we want the unit test getAge() method, which 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()); } } 

It works great in production. But the unit test should either set the system date to a known value, or be updated every year, expecting that the returned age will be increased by one, both are pretty powerful solutions.

A better solution for a unit test would be to introduce on a known date, while 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 the scenario with which a person’s birthday has passed since the creation of the object. With this implementation, getAge() will be based on when the Person object was created, not the current date. We can solve this 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 result will be correct:

 John Doe is 5 John Doe is 6 

Our unit test can enter the date "now" as follows:

 @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()); } 
+1
source

Source: https://habr.com/ru/post/1258760/


All Articles