Definition
- Supplier
has a single get()method taking no input and returning a value. - Laziness: the object is built only when
get()is called, not when the Supplier is defined. - orElseGet(supplier) defers construction to the empty case.
- orElse(value) eagerly evaluates the default even when unused.
- Stream.generate(supplier) produces values on demand.
Priya at the National Bank of India keeps a stamp that prints a blank default employee form on demand. Whenever she needs one, she presses the stamp. No inputs needed, out comes a fresh default.
Understanding the Concepts
How do you define a Supplier?
A Supplier has no arguments and returns a value each time get() is called.
package com.bank.hr;
import java.util.function.Supplier;
import java.util.Optional;
public class SupplierDemo {
public static void main(String[] args) {
Supplier<Employee> defaultEmployee =
() -> new Employee("UNKNOWN", "Unassigned", 0.0);
// Called only when needed
Employee e = defaultEmployee.get();
System.out.println(e.getName()); // UNKNOWN
// Used with Optional.orElseGet
Optional<Employee> empty = Optional.empty();
Employee fallback = empty.orElseGet(defaultEmployee);
System.out.println(fallback.getName()); // UNKNOWN
}
}
UNKNOWN
UNKNOWN
What is the difference between orElse and orElseGet?
| Method | When default is evaluated | Use when |
|---|---|---|
| orElse(value) | Always, even when Optional has a value | Default is cheap and pre-computed |
| orElseGet(supplier) | Only when Optional is empty | Default is expensive or has side-effects |
// WRONG: expensive default created even when not needed
Optional<Employee> present = Optional.of(existingEmployee);
Employee e1 = present.orElse(expensiveDbLookup());
// expensiveDbLookup() was called for nothing!
// CORRECT: lazy evaluation
Employee e2 = present.orElseGet(() -> expensiveDbLookup());
// expensiveDbLookup() is NOT called because present has a value
How do you use Supplier with Stream.generate?
import java.util.stream.Stream;
// Generate 5 default employees
Stream.generate(defaultEmployee)
.limit(5)
.forEach(e -> System.out.println(e.getName()));
UNKNOWN
UNKNOWN
UNKNOWN
UNKNOWN
UNKNOWN
What are common mistakes?
Mistake: confusing orElse with orElseGet.
// Both return the same result, but orElse always evaluates the argument:
Optional<Employee> opt = Optional.of(employee);
opt.orElse(new Employee("Default")); // Employee created, then discarded
opt.orElseGet(() -> new Employee("Default")); // Lambda never called
What about BooleanSupplier and other specialised suppliers?
Java provides specialised suppliers for primitives to avoid boxing.
import java.util.function.IntSupplier;
IntSupplier accountCounter = () -> 1001; // no boxing
int id = accountCounter.getAsInt();
What should a senior engineer know?
- Supplier defers construction: you pay the cost only when the value is consumed.
- Use supplier-form logging (log.info(() -> msg)) so the message string is assembled only when the level is enabled.
- Supplier is commonly used in collector factories, map computation (computeIfAbsent), and lazy initialization.
- A Supplier can return a different value on each call (new object) or always the same (cached value).
What are common interview follow-up questions?
- "What is the difference between Supplier and Callable?" Callable can throw checked exceptions; Supplier cannot.
- "Can a Supplier take arguments?" No; use Function for one argument or BiFunction for two.
- "How do you create a Supplier from a constructor?" Employee::new serves as Supplier
when matching the no-arg constructor.
Visual Overview
Supplier<Employee> () -> new Employee("UNKNOWN")
Not called yet → no object created
Optional.empty()
│
│ .orElseGet(supplier)
│ Optional is empty → call supplier.get()
▼
new Employee("UNKNOWN") ← created on demand
Optional.of(existing)
│
│ .orElseGet(supplier)
│ Optional has value → supplier NOT called
▼
existing ← supplier was never invoked
Key Takeaway
A Supplier is a functional interface with a no-argument get() method that returns a value. Its key benefit is laziness: the value is created only when get() is called, not when the Supplier is defined.
This is why orElseGet(supplier) is better than orElse(value) when the default is expensive: orElse always evaluates its argument, while orElseGet calls the supplier only when the Optional is empty. At the National Bank of India, the account lookup used orElseGet to avoid constructing a default employee object on every successful find.
Supplier is also the factory behind Stream.generate for on-demand value production and behind computeIfAbsent for lazy map population.
Remember one sentence: Supplier defers construction to when get() is called, and orElseGet uses that laziness to avoid building a default when the Optional already has a value.
---