Below are simple examples of how Java's built-in functional interfaces (from java.util.function package) can be used with lambda expressions.
Takes one argument and returns nothing.
import java.util.function.Consumer;
public class Test {
public static void main(String[] args) {
Consumer<String> consumer = (s) -> System.out.println("Hello " + s);
consumer.accept("World");
}
}Takes no arguments and returns a value.
import java.util.function.Supplier;
public class Test {
public static void main(String[] args) {
Supplier<String> supplier = () -> "Java is fun!";
System.out.println(supplier.get());
}
}Takes one argument and returns a result.
import java.util.function.Function;
public class Test {
public static void main(String[] args) {
Function<Integer, String> function = (x) -> "Result: " + (x * 2);
System.out.println(function.apply(5));
}
}Takes one argument and returns a boolean.
import java.util.function.Predicate;
public class Test {
public static void main(String[] args) {
Predicate<Integer> isEven = (x) -> x % 2 == 0;
System.out.println(isEven.test(4)); // true
System.out.println(isEven.test(5)); // false
}
}Takes two arguments and returns a result.
import java.util.function.BiFunction;
public class Test {
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 4)); // 7
}
}Takes two arguments and returns nothing.
import java.util.function.BiConsumer;
public class Test {
public static void main(String[] args) {
BiConsumer<String, Integer> printer = (name, age) -> System.out.println(name + " is " + age + " years old");
printer.accept("Alice", 30);
}
}A specialization of Function<T, T> — takes one argument and returns a result of the same type.
import java.util.function.UnaryOperator;
public class Test {
public static void main(String[] args) {
UnaryOperator<Integer> square = (x) -> x * x;
System.out.println(square.apply(6)); // 36
}
}A specialization of BiFunction<T, T, T> — takes two arguments of the same type and returns one of the same type.
import java.util.function.BinaryOperator;
public class Test {
public static void main(String[] args) {
BinaryOperator<Integer> multiply = (a, b) -> a * b;
System.out.println(multiply.apply(3, 7)); // 21
}
}Here’s a summary table of the most commonly used Java built-in functional interfaces from the java.util.function package with their descriptions, method names, and sample usage:
| Interface | Input(s) | Return Type | Method Name | Example Expression |
|---|---|---|---|---|
| Consumer | T | void | accept(T) |
x -> System.out.println(x) |
| Supplier | none | T | get() |
() -> "Hello" |
| Function<T, R> | T | R | apply(T) |
x -> x + 10 |
| Predicate | T | boolean | test(T) |
x -> x % 2 == 0 |
| BiConsumer<T, U> | T, U | void | accept(T, U) |
(x, y) -> System.out.println(x + y) |
| BiFunction<T, U, R> | T, U | R | apply(T, U) |
(x, y) -> x + y |
| UnaryOperator | T | T | apply(T) |
x -> x * x |
| BinaryOperator | T, T | T | apply(T, T) |
(x, y) -> x + y |
Below are 1–2 practical examples of each major functional interface being used with Java Streams.
import java.util.List;
import java.util.stream.Collectors;
import java.util.function.Predicate;
public class Test {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
Predicate<Integer> isEven = x -> x % 2 == 0;
List<Integer> evens = numbers.stream()
.filter(isEven) // filter using Predicate
.collect(Collectors.toList());
System.out.println(evens); // [2, 4, 6]
}
}import java.util.List;
import java.util.stream.Collectors;
import java.util.function.Function;
public class Test {
public static void main(String[] args) {
List<String> names = List.of("alice", "bob");
Function<String, String> toUpper = name -> name.toUpperCase();
List<String> upperNames = names.stream()
.map(toUpper) // map using Function
.collect(Collectors.toList());
System.out.println(upperNames); // [ALICE, BOB]
}
}import java.util.List;
import java.util.function.Consumer;
public class Test {
public static void main(String[] args) {
List<String> list = List.of("Java", "Python", "C++");
Consumer<String> printer = x -> System.out.println("Language: " + x);
list.stream().forEach(printer); // forEach using Consumer
}
}import java.util.function.Supplier;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
Supplier<Double> randomSupplier = () -> Math.random();
Stream.generate(randomSupplier) // generates infinite stream
.limit(5)
.forEach(System.out::println); // prints 5 random numbers
}
}🧪 5. BiFunction<T, U, R> – Combine two inputs to produce an output (used via .map() or custom collectors)
import java.util.function.BiFunction;
public class Test {
public static void main(String[] args) {
BiFunction<String, Integer, String> repeater = (str, times) -> str.repeat(times);
System.out.println(repeater.apply("Hi ", 3)); // Hi Hi Hi
}
}Usage in stream:
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.IntStream;
public class Test {
public static void main(String[] args) {
List<String> words = List.of("Hi", "Bye");
BiFunction<String, Integer, String> repeater = (s, count) -> s.repeat(count);
IntStream.range(0, words.size())
.mapToObj(i -> repeater.apply(words.get(i), i + 1))
.forEach(System.out::println);
// Hi
// ByeBye
}
}import java.util.Map;
import java.util.function.BiConsumer;
public class Test {
public static void main(String[] args) {
Map<String, Integer> map = Map.of("apple", 2, "banana", 3);
BiConsumer<String, Integer> printer = (k, v) -> System.out.println(k + " -> " + v);
map.forEach(printer); // BiConsumer with Map
}
}import java.util.List;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3);
UnaryOperator<Integer> square = x -> x * x;
List<Integer> squared = list.stream()
.map(square) // same input and output type
.collect(Collectors.toList());
System.out.println(squared); // [1, 4, 9]
}
}import java.util.List;
import java.util.function.BinaryOperator;
public class Test {
public static void main(String[] args) {
List<Integer> nums = List.of(1, 2, 3, 4);
BinaryOperator<Integer> sum = (a, b) -> a + b;
int total = nums.stream().reduce(0, sum); // reduce using BinaryOperator
System.out.println(total); // 10
}
}| Interface | Common Stream Use |
|---|---|
Predicate<T> |
.filter() |
Function<T, R> |
.map() |
Consumer<T> |
.forEach() |
Supplier<T> |
Stream.generate() |
BiFunction<T,U,R> |
custom .map() or .reduce() |
BiConsumer<T,U> |
Map.forEach() |
UnaryOperator<T> |
.map() for same-type conversion |
BinaryOperator<T> |
.reduce() |
- It represents a function that takes no input and returns a value of type
T. - Method:
T get() - Use case: When you want to supply or generate values on-demand (e.g., default values, random numbers, UUIDs, timestamps, etc.)
import java.util.function.Supplier;
import java.util.Random;
import java.util.stream.Stream;
public class SupplierExample {
public static void main(String[] args) {
Supplier<String> otpSupplier = () -> {
Random random = new Random();
StringBuilder otp = new StringBuilder();
for (int i = 0; i < 6; i++) {
otp.append(random.nextInt(10)); // digit 0–9
}
return otp.toString();
};
// Generate 5 OTPs using Stream.generate + Supplier
Stream.generate(otpSupplier)
.limit(5)
.forEach(System.out::println);
}
}483920
129457
504612
877324
032185
Each time you run the program, it will generate 5 random 6-digit OTPs.
| Use Case | Example Output |
|---|---|
| Generate random values | Random number, OTP, UUID |
| Provide default values | Empty list, "N/A", 0 |
| Lazy initialization | Only compute if needed |
| Timestamp generation | Instant.now() |
| Resource loading (on-demand) | Read file/config when needed |