Complete Java Supplier interface tutorial covering all methods with examples. Learn about functional programming in Java.
Last modified: April 16, 2025
The java.util.function.Supplier interface represents a supplier of results. It is a functional interface with a single abstract method get. Supplier doesn’t accept any arguments but produces a value.
Supplier is part of Java’s functional programming utilities added in Java 8. It is useful for lazy evaluation, object creation, and value generation scenarios. The interface is often used with Optional and Streams.
Supplier interface contains one abstract method and no default methods. The key method get returns a result without taking any input parameters. It’s a pure producer of values.
@FunctionalInterface public interface Supplier<T> { T get(); }
The code above shows the simple structure of Supplier interface. It uses generics where T is the type of results supplied. The interface is annotated with @FunctionalInterface to indicate its single abstract method.
The simplest way to use Supplier is with lambda expressions. We define how to generate values in the get method. The example supplies random numbers.
Main.java
package com.zetcode;
import java.util.function.Supplier; import java.util.Random;
public class Main {
public static void main(String[] args) {
// Define a supplier for random numbers
Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);
// Get values from supplier
System.out.println("Random 1: " + randomSupplier.get());
System.out.println("Random 2: " + randomSupplier.get());
// Supplier for current timestamp
Supplier<Long> timeSupplier = System::currentTimeMillis;
System.out.println("Current time: " + timeSupplier.get());
}
}
This example demonstrates basic Supplier usage with lambda and method reference. The randomSupplier generates random integers when get() is called. The timeSupplier uses method reference to supply current timestamps.
Supplier is commonly used for object creation, especially when you need to defer instantiation or create objects on demand. This enables lazy evaluation.
Main.java
package com.zetcode;
import java.util.function.Supplier;
class Product { private String name; private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
System.out.println("Creating product: " + name);
}
@Override
public String toString() {
return name + " ($" + price + ")";
}
}
public class Main {
public static void main(String[] args) {
// Supplier for product creation
Supplier<Product> productSupplier = () -> new Product("Laptop", 999.99);
System.out.println("Supplier defined, but product not created yet");
// Only creates product when get() is called
Product p1 = productSupplier.get();
Product p2 = productSupplier.get();
System.out.println("Products created: " + p1 + ", " + p2);
}
}
This example shows Supplier used for deferred object creation. The Product objects are only instantiated when get() is called. This demonstrates lazy initialization pattern using Supplier.
Supplier is often used with Optional’s orElseGet method to provide a fallback value only when needed. This is more efficient than orElse when the fallback is expensive to create.
Main.java
package com.zetcode;
import java.util.Optional; import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
Optional<String> emptyOptional = Optional.empty();
Optional<String> presentOptional = Optional.of("Hello");
// Expensive fallback operation
Supplier<String> fallbackSupplier = () -> {
System.out.println("Creating fallback value");
return "Default Value";
};
// orElseGet uses Supplier (lazy)
String value1 = emptyOptional.orElseGet(fallbackSupplier);
String value2 = presentOptional.orElseGet(fallbackSupplier);
System.out.println("Value 1: " + value1);
System.out.println("Value 2: " + value2);
// Compare with orElse (eager)
String value3 = emptyOptional.orElse(fallbackSupplier.get());
}
}
This example demonstrates Supplier with Optional. The fallbackSupplier only executes when Optional is empty. Using orElseGet with Supplier is more efficient than orElse when fallback creation is expensive.
The Stream.generate() method accepts a Supplier to create infinite streams. This is useful for generating sequences of values where each is produced by the Supplier.
Main.java
package com.zetcode;
import java.util.stream.Stream; import java.util.function.Supplier; import java.util.concurrent.ThreadLocalRandom; import java.util.List; import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// Supplier for random doubles between 0 and 1
Supplier<Double> randomSupplier =
() -> ThreadLocalRandom.current().nextDouble();
// Generate infinite stream of random numbers
List<Double> randoms = Stream.generate(randomSupplier)
.limit(5)
.collect(Collectors.toList());
System.out.println("Random numbers: " + randoms);
// Supplier for sequence numbers
Supplier<Integer> sequenceSupplier = new Supplier<>() {
private int next = 0;
@Override
public Integer get() {
return next++;
}
};
List<Integer> sequence = Stream.generate(sequenceSupplier)
.limit(5)
.collect(Collectors.toList());
System.out.println("Sequence: " + sequence);
}
}
This example shows Supplier used with Stream.generate(). The randomSupplier produces random numbers, while sequenceSupplier maintains state to generate a sequence. Both demonstrate infinite stream generation capabilities.
Supplier can be used to implement memoization - caching the result of an expensive computation and returning it on subsequent calls. This pattern optimizes performance.
Main.java
package com.zetcode;
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
// Expensive computation simulation
Supplier<String> expensiveSupplier = () -> {
System.out.println("Performing expensive computation...");
try {
Thread.sleep(1000); // Simulate work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Computed Result";
};
// Memoizing supplier
Supplier<String> memoizedSupplier = new Supplier<>() {
private String value;
@Override
public String get() {
if (value == null) {
value = expensiveSupplier.get();
}
return value;
}
};
System.out.println("First call (computes): " + memoizedSupplier.get());
System.out.println("Second call (cached): " + memoizedSupplier.get());
}
}
This example demonstrates memoization using Supplier. The expensive computation only happens on the first get() call. Subsequent calls return the cached value. This pattern is useful for expensive operations that produce the same result.
Java provides specialized Supplier variants for primitive types to avoid boxing overhead. These include BooleanSupplier, IntSupplier, LongSupplier, and DoubleSupplier.
Main.java
package com.zetcode;
import java.util.function.*;
public class Main {
public static void main(String[] args) {
// BooleanSupplier example
BooleanSupplier booleanSupplier = () -> Math.random() > 0.5;
System.out.println("Random boolean: " + booleanSupplier.getAsBoolean());
// IntSupplier example
IntSupplier intSupplier = () -> (int) (Math.random() * 100);
System.out.println("Random int: " + intSupplier.getAsInt());
// LongSupplier example
LongSupplier longSupplier = System::currentTimeMillis;
System.out.println("Current time: " + longSupplier.getAsLong());
// DoubleSupplier example
DoubleSupplier doubleSupplier = Math::random;
System.out.println("Random double: " + doubleSupplier.getAsDouble());
}
}
This example shows specialized Supplier interfaces. Each avoids boxing overhead for its primitive type. They follow the same pattern as the generic Supplier but with type-specific get methods (getAsBoolean, getAsInt, etc.).
Java Supplier Interface Documentation
In this article, we’ve covered the essential methods and features of the Java Supplier interface. Understanding these concepts is crucial for functional programming and efficient value generation in Java applications.
My name is Jan Bodnar, and I am a dedicated programmer with many years of experience in the field. I began writing programming articles in 2007 and have since authored over 1,400 articles and eight e-books. With more than eight years of teaching experience, I am committed to sharing my knowledge and helping others master programming concepts.
List all Java tutorials.