← Back to Advanced Java Course | Chapter 3: Functional Programming | Lesson 2 of 6

Java Functional Interfaces

What is a Functional Interface?

A functional interface is any interface that contains exactly one abstract method, making it a valid target for a lambda expression or method reference. You can (and should) annotate one with @FunctionalInterface, which tells the compiler to verify the interface truly has just one abstract method and fail the build otherwise.

Example: What is a Functional Interface?

java
public class Main {
	@FunctionalInterface
	interface Operation {
		int apply(int a, int b);
	}
	public static void main(String[] args) {
		Operation add = (a, b) -> a + b;
		System.out.println(add.apply(2, 3));
	}
}

The Predicate Interface

The Predicate interface is a built-in functional interface that accepts a single argument and returns a boolean, making it the standard shape for filtering conditions. It lives in the java.util.function package alongside Java's other general-purpose functional interfaces.

Example: The Predicate Interface

java
import java.util.function.Predicate;
public class Main {
	public static void main(String[] args) {
		Predicate<Integer> isEven = n -> n % 2 == 0;
		System.out.println(isEven.test(4));
		System.out.println(isEven.test(7));
	}
}

The Function Interface

The Function interface accepts a single argument of one type and returns a result of a potentially different type, representing a transformation from input to output. It's commonly used for data conversion or mapping operations, such as turning a String into an Integer.

Example: The Function Interface

java
import java.util.function.Function;
public class Main {
	public static void main(String[] args) {
		Function<String, Integer> toLength = s -> s.length();
		System.out.println(toLength.apply("hello"));
	}
}

Consumer and Supplier

The Consumer interface accepts a single argument and returns no result, representing an operation performed purely for its side effect, like printing a value. The Supplier interface is its mirror image: it accepts no arguments at all and simply produces a generated result on demand.

Example: Consumer and Supplier

java
import java.util.function.Consumer;
import java.util.function.Supplier;
public class Main {
	public static void main(String[] args) {
		Consumer<String> printer = s -> System.out.println("Got: " + s);
		Supplier<String> generator = () -> "generated value";
		printer.accept(generator.get());
	}
}

BiFunctional Interfaces

Java also provides two-argument variants of these core interfaces for cases involving pairs of values: BiFunction accepts two arguments and returns a computed result, while BiConsumer accepts two arguments and performs a side effect without returning anything.

Example: BiFunctional Interfaces

java
import java.util.function.BiFunction;
import java.util.function.BiConsumer;
public class Main {
	public static void main(String[] args) {
		BiFunction<Integer, Integer, Integer> multiply = (a, b) -> a * b;
		BiConsumer<String, Integer> log = (name, age) -> System.out.println(name + " is " + age);
		System.out.println(multiply.apply(3, 4));
		log.accept("Sam", 30);
	}
}
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.