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;
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;
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()); }