10.1. Supplier Interface
The Supplier interface is a functional interface in Java that represents a supplier of results. It has a single method get()
that returns a value without taking any input parameters.
Supplier Interface Definition
java
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Key Characteristics
- No input parameters: The
get()
method takes no arguments - Returns a value: Produces a result of specified type
- Lazy evaluation: Computation happens only when
get()
is called - Functional interface: Can be used with lambda expressions and method references
Basic Supplier Examples
Simple Value Supplier
java
import java.util.function.Supplier;
public class BasicSupplier {
public static void main(String[] args) {
// Supplier that provides a constant string
Supplier<String> messageSupplier = () -> "Hello, World!";
System.out.println(messageSupplier.get()); // Output: Hello, World!
// Supplier that provides current timestamp
Supplier<Long> timestampSupplier = () -> System.currentTimeMillis();
System.out.println("Current time: " + timestampSupplier.get());
}
}
Object Creation Supplier
java
import java.util.function.Supplier;
import java.util.ArrayList;
import java.util.List;
public class ObjectSupplier {
public static void main(String[] args) {
// Supplier for new ArrayList
Supplier<List<String>> listSupplier = () -> new ArrayList<>();
List<String> names = listSupplier.get();
names.add("Alice");
names.add("Bob");
System.out.println("List: " + names); // Output: List: [Alice, Bob]
// Supplier for new StringBuilder
Supplier<StringBuilder> stringBuilderSupplier = StringBuilder::new;
StringBuilder sb = stringBuilderSupplier.get();
sb.append("Hello");
System.out.println(sb.toString()); // Output: Hello
}
}
Supplier with State
Suppliers can maintain state through captured variables:
java
import java.util.function.Supplier;
public class StatefulSupplier {
public static void main(String[] args) {
// Supplier with counter state
class CounterSupplier implements Supplier<Integer> {
private int count = 0;
@Override
public Integer get() {
return ++count;
}
}
CounterSupplier counter = new CounterSupplier();
System.out.println(counter.get()); // Output: 1
System.out.println(counter.get()); // Output: 2
System.out.println(counter.get()); // Output: 3
}
}
Common Use Cases
1. Default Value Provider
java
import java.util.function.Supplier;
public class DefaultValueSupplier {
public static <T> T getOrDefault(T value, Supplier<T> defaultValueSupplier) {
return (value != null) ? value : defaultValueSupplier.get();
}
public static void main(String[] args) {
String name = null;
// Provide default value using Supplier
String result = getOrDefault(name, () -> "Unknown User");
System.out.println("Name: " + result); // Output: Name: Unknown User
// With non-null value
String actualName = "Alice";
String result2 = getOrDefault(actualName, () -> "Unknown User");
System.out.println("Name: " + result2); // Output: Name: Alice
}
}
2. Lazy Initialization
java
import java.util.function.Supplier;
public class LazyInitialization {
private static class HeavyObject {
public HeavyObject() {
System.out.println("HeavyObject created - expensive operation!");
// Simulate expensive initialization
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
public void use() {
System.out.println("Using HeavyObject");
}
}
public static void main(String[] args) {
// Lazy initialization using Supplier
Supplier<HeavyObject> heavyObjectSupplier = () -> {
System.out.println("Creating HeavyObject...");
return new HeavyObject();
};
System.out.println("Program started");
System.out.println("HeavyObject not created yet");
// Object created only when needed
HeavyObject obj = heavyObjectSupplier.get();
obj.use();
}
}
3. Configuration Supplier
java
import java.util.function.Supplier;
import java.util.Properties;
public class ConfigurationSupplier {
private static Properties config = new Properties();
static {
config.setProperty("app.name", "MyApplication");
config.setProperty("app.version", "1.0.0");
config.setProperty("database.url", "jdbc:mysql://localhost:3306/mydb");
}
public static void main(String[] args) {
// Suppliers for configuration values
Supplier<String> appNameSupplier = () -> config.getProperty("app.name");
Supplier<String> dbUrlSupplier = () -> config.getProperty("database.url");
Supplier<String> missingConfigSupplier = () -> config.getProperty("missing.key", "default");
System.out.println("App Name: " + appNameSupplier.get());
System.out.println("DB URL: " + dbUrlSupplier.get());
System.out.println("Missing Key: " + missingConfigSupplier.get());
}
}
Specialized Suppliers
Java provides specialized Supplier interfaces for primitive types:
BooleanSupplier
java
import java.util.function.BooleanSupplier;
public class BooleanSupplierExample {
public static void main(String[] args) {
BooleanSupplier isEven = () -> System.currentTimeMillis() % 2 == 0;
BooleanSupplier isAdmin = () -> "admin".equals(System.getProperty("user.role"));
System.out.println("Is even timestamp: " + isEven.getAsBoolean());
System.out.println("Is admin: " + isAdmin.getAsBoolean());
}
}
IntSupplier, LongSupplier, DoubleSupplier
java
import java.util.function.IntSupplier;
import java.util.function.LongSupplier;
import java.util.function.DoubleSupplier;
public class PrimitiveSuppliers {
public static void main(String[] args) {
IntSupplier randomInt = () -> (int) (Math.random() * 100);
LongSupplier currentTime = System::currentTimeMillis;
DoubleSupplier randomDouble = Math::random;
System.out.println("Random int: " + randomInt.getAsInt());
System.out.println("Current time: " + currentTime.getAsLong());
System.out.println("Random double: " + randomDouble.getAsDouble());
}
}
Best Practices
- Use for lazy evaluation: Delay expensive computations until needed
- Prefer method references: Use
ClassName::new
for object creation - Maintain immutability: Suppliers should be stateless when possible
- Handle exceptions: Wrap checked exceptions in runtime exceptions
java
import java.util.function.Supplier;
public class SafeSupplier {
public static <T> Supplier<T> wrap(Supplier<T> supplier, T defaultValue) {
return () -> {
try {
return supplier.get();
} catch (Exception e) {
System.err.println("Error in supplier: " + e.getMessage());
return defaultValue;
}
};
}
public static void main(String[] args) {
Supplier<String> unsafeSupplier = () -> {
if (Math.random() > 0.5) {
throw new RuntimeException("Random failure");
}
return "Success";
};
Supplier<String> safeSupplier = wrap(unsafeSupplier, "Default Value");
for (int i = 0; i < 5; i++) {
System.out.println("Result: " + safeSupplier.get());
}
}
}