What is the Java Supplier interface?
java.util.function.Supplier<T> is one of Java's core functional interfaces. A Supplier accepts no arguments and returns a value of type T.
Conceptually, its single abstract method looks like this:
@FunctionalInterface
public interface Supplier<T> {
T get();
}A Supplier is useful whenever code needs a value but should not care exactly how that value is created. The supplied value might come from a calculation, object factory, cache, random-number generator or another source.
Supplier vs. Consumer vs. Function
The three interfaces describe different data flows:
Supplier<T>takes no argument and returns a value.Consumer<T>accepts a value and returns no result.Function<T,R>accepts a value and returns another value.
A Supplier does not guarantee that every call returns a new or distinct object. Repeated calls are allowed to return the same value.
Implement Supplier with a Java class
The following class supplies a random digit from 0 through 9. A single Random instance is reused rather than creating a new random-number generator every time get() is called.
package com.mcnz.supplier.example;
import java.util.random.RandomGenerator;
import java.util.function.Supplier;
public class RandomDigitSupplier
implements Supplier<Integer> {
private final RandomGenerator random = RandomGenerator.getDefault();
@Override
public Integer get() {
return random.nextInt(10);
}
}To use the Supplier, create it once and call get() whenever a value is needed.
public class SupplierExampleRunner {
public static void main(String[] args) {
Supplier<Integer> digits =
new RandomDigitSupplier();
for (int i = 0; i < 10; i++) {
IO.print(digits.get() + " ");
}
}
}A test run of the Supplier interface example generated the following results:
5 4 0 0 9 0 4 2 4 5Supplier lambda expression example
Because Supplier<T> is a functional interface, a separate implementation class is often unnecessary. The same behavior can be expressed with a lambda:
import java.util.random.RandomGenerator;
import java.util.function.Supplier;
public class SupplierLambdaExample {
public static void main(String[] args) {
var random = RandomGenerator.getDefault();
Supplier<Integer> digitSupplier =
() -> random.nextInt(10);
for (int i = 0; i < 10; i++) {
IO.print(digitSupplier.get() + " ");
}
}
}The lambda has no parameters, which is why it begins with empty parentheses. Its expression returns the value produced by Supplier.get().
Supplier with a method reference
If an existing no-argument method already returns the required type, a method reference can be even simpler.
import java.util.UUID;
import java.util.function.Supplier;
Supplier<UUID> uuidSupplier =
UUID::randomUUID;
UUID id = uuidSupplier.get();Here, UUID.randomUUID() takes no arguments and returns a UUID, so its signature matches Supplier<UUID>.
Primitive Supplier interfaces
Java also provides primitive specializations that avoid boxing values into wrapper objects:
IntSupplierreturns anintthroughgetAsInt().LongSupplierreturns alongthroughgetAsLong().DoubleSupplierreturns adoublethroughgetAsDouble().BooleanSupplierreturns abooleanthroughgetAsBoolean().
import java.util.random.RandomGenerator;
import java.util.function.IntSupplier;
var random = RandomGenerator.getDefault();
IntSupplier digitSupplier =
() -> random.nextInt(10);
int digit = digitSupplier.getAsInt();If the supplied result is naturally primitive, these specialized interfaces can be preferable to Supplier<Integer>, Supplier<Long> or Supplier<Double>.
Use Supplier with Stream.generate()
One of the clearest uses of Supplier in the standard Java API is Stream.generate(). The stream repeatedly calls a Supplier to obtain elements.
import java.util.UUID;
import java.util.stream.Stream;
Stream.generate(UUID::randomUUID)
.limit(5)
.forEach(IO::println);Without limit(), a stream created by Stream.generate() is unbounded, so a terminating operation normally needs some way to restrict how many elements are consumed.
When should you use Supplier?
Use Supplier<T> when a caller needs to obtain a value without supplying an input argument. Common examples include lazy value creation, factories, default-value generation, deferred calculations and APIs such as Stream.generate().
The easiest way to remember Java's Supplier interface is by its shape: no input, one output. Once that model is clear, Supplier lambdas and method references become straightforward.