The Key Functional Interfaces you must know

Vikas Taank
3 min readDec 26, 2023

Functional Interface is an interface introduced in Java 8 in order to support functional programming and Lambda use cases. I want to introduce you to functional interfaces in a very simple manner.

By definition a functional interface must have a single abstract method and it can have any number of default and static methods. It is characterized by the annotation @FunctionalInterface But that is not mandatory.

When compiler finds a single abstract method it knows that it's a functional interface.

Now Interviewer may ask that need of Default Methods and the Simple Answer is the Backward compatibility.

When Java 8 incorporated features like the Streams API, it required adding new methods to existing interfaces like List or Collection. Without default methods, adding these new methods would have broken the existing implementations of these interfaces.

Java does not support multiple inheritance of classes however with the use of functional interface now with default methods it can provide the multiple inheritance of behavior. This feature allows classes to inherit multiple behavior from interfaces.

Key Functional Interfaces:

Runnable:

@FunctionalInterface
public interface Runnable {
void run();
}

It can be used in Lambda expression Like this:

Runnable r = () -> System.out.println("Running");

Comparator

@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);

// Other default and static methods...
}

Method Definition

  • compare(T o1, T o2): This method compares its two arguments for order. It returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

Return Value

  • A negative integer if o1 is less than o2.
  • Zero if o1 is equal to o2.
  • A positive integer if o1 is greater than o2.
Comparator<String> stringComparison = (s1, s2) -> Integer.compare(s1.length(), s2.length());

// Usage in a sort method
List<String> strings = Arrays.asList("Lambda", "Functional", "Interface", "Java");
strings.sort(stringComparison);

Consumer:

@FunctionalInterface
public interface Consumer<T> {
void accept(T t);

// Other default and static methods...
}

This interface is commonly used in Lambda expression in order to consume a value and it does not return any value.

For example if you want to print something , you would want to use Consumer interface.

import java.util.stream.Stream;

public class ConsumerForEachExample {
public static void main(String[] args) {
Stream.of("Vikas", "Java", "Medium")
.forEach(System.out::println); // Consumer provided via method reference
}
}

You can use this to consume and modify a collection:

import java.util.function.Consumer;
import java.util.List;
import java.util.ArrayList;

public class ConsumeExample {
static class Location {
String name;
Location(String name) { this.name = name; }
void setName(String ip) { this.name = name; }
String getName() { return this.name; }
}

public static void main(String[] args) {
List<Location> locations = new ArrayList<>();
users.add(new Location("Ashburn"));
users.add(new Location("Broadlands"));

Consumer<Location> capitalizeLocation = location -> location.setName(location.getName().toUpperCase());

locations.forEach(capitalizeLocation); // Capitalize the Locations

users.forEach(location -> System.out.println(location.getName())); // Print capitalized locations
}
}

Predicate:

This is mostly used to evaluate and condition and return true and false.

@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);

// Other default and static methods...
}

If I have to print numbers from a list which are greater than 5 I can use Predicate in a Lmabda expression.

       List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

numbers.stream().filter(x-> x>5).collect(Collectors.toList()).
// Here Predicate is x- > x>5
//It could e written like that as well.
Predicate predicate= number -> number >5
numbers.stream().filter(predicate).collect(Collectors.toList()).

Supplier:

Supplier is jus returns a value and it is used to supply new objects.

@FunctionalInterface
public interface Supplier<T> {
T get();
}

Examples could be like this:

import java.util.function.Supplier;
import java.util.Random;

public class Example {
public static void main(String[] args) {

Supplier<Double> doubleSupplier = Math::random;

Double value1 = doubleSupplier.get(); // A random value provided
Double value2 = doubleSupplier.get(); // Another Random Value

System.out.println(value1);
System.out.println(value2);
}
}

Just wanted to share some of the most common Functional Interface with the simplicity and ease of understanding, most of experienced developers will find it redundant but it’s a quick reference. Please share and clap if you liked my content.

--

--

Vikas Taank

I am new to Medium, trying to articulate my learnings so far . Please Join medium to read my articles. Please support- https://ko-fi.com/vikastaank