General-purpose functional interfaces for use with lambdas

We have seen that we can define a functional interface as a "blueprint" for a Java lambda expression. The functional interface contains a single method defining the input parameters and return type of the lambda. This is quite a neat solution, as it means that many methods that previously required an interface instance to be passed into them will now automatically work with lambda expressions. In our introduction to lambdas, we saw examples with Comparator and Runnable.

That's all very well for backwards compatibility, but what about new methods where in reality, we are only ever intending to pass in a lambda expression? If our lambda expression happens to match the arguments of a pre-existing interface such as Runnable or Comparator, we can define our method to take, say, a Comparator, even though we will always be passing in a lambda expression. And for methods where we want to pass in a lambda with some other combination of arguments, we can define a functional interface accordingly. But if we are making frequent use of lambdas, it will soon become inconvenient to have to declare a functional interface for every distinct combination of lambvda arguments that we happen to use. And some of these will be quite common. For example, a common case might be to define methods that take a "filter" expression, i.e. a lambda that takes a single argument and returns a boolean. Another common case would be a "getter": a lambda that defines how to return some field from an object, such as our "get description" example on the previous page.

To alleviate the need to define new interfaces for common combinations of lambda parameters, Java 8 comes with a set of general-purpose functional interfaces.

For example, the Function interface is a general-purpose functional interface for lambda expressions that take one object as their input argument and return an object. Ignoring some details, it is essentially defined as follows:

public interface Function<T, R> {

    R apply(T t);	

As you can see, Function is a generic interface, meaning that we can parameterise it with the specific classes of objects in question. Our DescriptionGetter interface from the previous funtional interface example takes a DataItem and returns a String. Therefore, it is effectively equivalent to Function<DataItem, String> and we can re-implement our previous example as follows:

public static List<String> getItemDescriptions(List<? extends DataItem> items, Function<DataItem, String> getter) {
	List<String> ret = new ArrayList(items.size());
	for (DataItem item : items) {
		String desc = getter.apply(item);
	return ret;

Functional interfaces are provided for a range of combinations of zero, one or two input parameters and various return types. Another interface that you will commonly use is Predicate. This provides a template for a lambda expression that takes an object and returns a boolean. It is therefore used in cases where the expression defines a filter or condition.

The following table summarises the various functional interfaces that are defined in the standard Java API:

Input parametersReturn
Object, ObjectBiConsumerBiFunctionBiPredicateToIntBiFunction

As you will glean from the table, the generic functional interfaces genreally follow a standard naming convention, distinguishing between:

The prefix Bi- is used to indicate two input parameters. The input or return type is generally considered to be an object unless a specific type is included in the name (in which case it generally refers to a primitive type). Where the type is included, it is prefixed with To- to indicate a return type rather than an argument type. In places where Int or Long appear in the interfaces listed above, Double is generally also possible.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.