Supplier
A Supplier is a functional interface in Java used when you need to obtain a value without providing an input value. It represents the idea of "give me a value when I ask for one."
This makes Supplier useful for generating values, creating objects, reading configuration values, producing default values, and delaying an operation until the value is actually needed.
What Is Supplier?
The Supplier<T> interface belongs to the java.util.function package.
@FunctionalInterface
public interface Supplier<T> {
T get();
}
The interface has one abstract method, get(). It accepts no arguments and returns a value of type T.
Remember: Supplier takes no input and produces one output. Its primary method is get().
Basic Supplier Example
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
Supplier<String> message =
() -> "Welcome to Java";
System.out.println(message.get());
}
}
The lambda has no parameters because the Supplier does not require input. When get() is called, the lambda produces a string.
Understanding Supplier<T>
The generic type T specifies the type of value that the Supplier produces.
| Supplier | Input | Output | Method |
|---|---|---|---|
| Supplier<String> | None | String | get() |
| Supplier<Integer> | None | Integer | get() |
| Supplier<Double> | None | Double | get() |
| Supplier<Student> | None | Student | get() |
Supplier with Numbers
A Supplier can generate a number whenever its get() method is called.
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
Supplier<Integer> number =
() -> 100;
System.out.println(number.get());
}
}
Every call returns the value produced by the lambda.
Supplier Can Produce Different Values
A Supplier does not have to return a fixed value. It can calculate or generate a value each time it is called.
import java.util.function.Supplier;
import java.util.Random;
public class Main {
public static void main(String[] args) {
Supplier<Integer> randomNumber =
() -> new Random().nextInt(100);
System.out.println(randomNumber.get());
System.out.println(randomNumber.get());
}
}
The Supplier creates a value when requested. Because the operation is executed during each get() call, the returned values can differ.
Supplier with Multiple Statements
A Supplier can contain multiple statements by using a block lambda.
Supplier<Integer> calculate =
() -> {
int first = 20;
int second = 30;
return first + second;
};
System.out.println(calculate.get());
Because the Supplier returns a value, a block-bodied lambda must use an explicit return statement.
Supplier with Custom Objects
A Supplier can also create and return application objects.
import java.util.function.Supplier;
class Student {
String name;
Student(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Supplier<Student> studentSupplier =
() -> new Student("Ravi");
Student student = studentSupplier.get();
System.out.println(student.name);
}
}
The Supplier stores the object-creation behavior. The actual Student object is created when get() is called.
Supplier for Default Values
Supplier is useful when a value should be generated only when it is actually required.
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
Supplier<String> defaultMessage =
() -> "Default message";
System.out.println(defaultMessage.get());
}
}
This pattern becomes particularly useful when generating the fallback value is expensive and should not happen unnecessarily.
Supplier and Lazy Evaluation
One important idea associated with Supplier is lazy evaluation. Instead of calculating a value immediately, you can store the operation and execute it later.
Supplier<String> message =
() -> {
System.out.println("Creating message...");
return "Hello";
};
System.out.println("Before get()");
System.out.println(message.get());
The code inside the Supplier does not execute when the Supplier is created. It executes when get() is called.
Think of a Supplier as a vending machine: you do not receive anything when you simply know the machine exists. You receive the value when you request it.
Supplier as a Method Parameter
A method can accept a Supplier when it needs a value but wants the caller to decide how that value should be produced.
import java.util.function.Supplier;
public class Main {
static void display(Supplier<String> supplier) {
System.out.println(supplier.get());
}
public static void main(String[] args) {
display(() -> "Java Programming");
display(() -> "Spring Boot");
}
}
The display() method does not know where the text comes from. It simply asks the Supplier for a value.
Supplier with a Method
A Supplier can also reference an existing method.
import java.util.function.Supplier;
public class Main {
static String getMessage() {
return "Hello from Java";
}
public static void main(String[] args) {
Supplier<String> supplier =
Main::getMessage;
System.out.println(supplier.get());
}
}
The method reference Main::getMessage provides the implementation expected by the Supplier.
Supplier vs Consumer
Supplier and Consumer represent opposite directions of data flow. A Supplier produces a value, while a Consumer receives a value and performs an action.
| Feature | Supplier | Consumer |
|---|---|---|
| Input | None | One value |
| Output | One value | None |
| Main method | get() | accept() |
| Purpose | Produce a value | Perform an action |
Supplier vs Function
A Function transforms an existing input, while a Supplier creates or provides a value without requiring input.
| Feature | Supplier | Function |
|---|---|---|
| Input | None | One value |
| Output | One value | One value |
| Main method | get() | apply() |
| Purpose | Provide or generate a value | Transform a value |
Supplier vs Predicate
Predicate tests a supplied input and returns a boolean. Supplier does not accept input and instead produces a value.
Predicate<Integer> positive =
number -> number > 0;
Supplier<Integer> number =
() -> 100;
The Predicate asks a question about a value. The Supplier provides a value.
Practical Example: Generating User IDs
import java.util.function.Supplier;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String[] args) {
AtomicInteger counter =
new AtomicInteger(1000);
Supplier<Integer> userId =
() -> counter.incrementAndGet();
System.out.println(userId.get());
System.out.println(userId.get());
System.out.println(userId.get());
}
}
The Supplier encapsulates the ID-generation logic. Every call to get() produces the next identifier.
Practical Example: Generating Configuration Values
import java.util.function.Supplier;
public class Main {
static void startApplication(
Supplier<String> environment) {
System.out.println(
"Environment: " + environment.get()
);
}
public static void main(String[] args) {
startApplication(() -> "Production");
}
}
The method receives a Supplier instead of a fixed string. This keeps value-generation logic separate from the code that consumes the value.
Common Beginner Mistakes
- Trying to pass a parameter to get().
- Forgetting that Supplier does not accept an input value.
- Confusing Supplier with Function, which requires an input.
- Assuming a Supplier always returns the same value.
- Calling get() repeatedly when the generated operation is expensive and the result should instead be cached.
Best Practices
- Use Supplier when a value should be produced without an input.
- Use Supplier to defer value creation until it is actually needed.
- Keep the supplied operation focused and predictable.
- Use method references when they make the Supplier easier to read.
- Be aware that each call to get() can execute the supplied logic again.
Interview Insight
Interview shortcut: Supplier<T> takes no arguments and returns a value of type T through its get() method. It is commonly used for value generation, lazy evaluation, and deferred object creation.
Quick Revision
| Concept | Key Point |
|---|---|
| Supplier<T> | Produces a value without receiving input |
| get() | Requests the supplied value |
| Input | None |
| Output | One value of type T |
| Lazy Evaluation | Logic executes when get() is called |
| Typical Use | Value generation, defaults, object creation, deferred operations |
Final Takeaway
A Supplier is the functional interface to remember whenever you need to produce a value without receiving an input. Its simple get() method makes it useful for generating values, creating objects, supplying defaults, and delaying work until it is actually required. Once you recognize the pattern "nothing goes in, something comes out," choosing Supplier becomes straightforward.
