Functional Interfaces

What is a functional interface? And what good are Lambdas?

We all know what an interface is. It is a contract with a list of abstract method headers. Any abstract class can say it implements an interface; concret children of such a class must implemnt the interfaces's methods.

Concrete classes must implement all methods of an interface to implement it. This is enforced by the compiler.

Lambdas are a new Java8 feature; they allow us to create anonymous functions. They can take several forms. First there is a "super-simple" lambda; this lambda has a tacit return of x*x..

x -> x*x;

This is a nameless function that accepts one parameter and which returns the result of multipling that value by itself. It makes sense for primitive numerical types.

You can have one of these with several variables like so.

(x, y) -> x*y;

You can have one of these an empty argument list like so.

() -> System.out.err("Your program just croaked");

Lambdas can also have blocks of code. If you do this, there is no tacit return. A lambda with a block looks like this.

x -> 
{
    int y = x*x;
    return y;
};

You can also specify types for arguments in a lambda and the compiler will do type checking.

(double x, double y) -> x*y;

New in Java 8

Interfaces have a new feature: default methods. If your concrete class implements an interface with default methods, it inherits the defaults, which it may accept or override.

Functional Interfaces An interface is functional if it specifies exactly one method. However, a functional interface can have other default methods.

Here are some familiar examples of functional interfaces. YOu will see in the docs that these interfaces are marked functional.

Java has a new package java.util.function that brims with functional interfaces.

Another is EventHandler<E>, which contains in its method handle(E e) the code to be fired in reponse to an event of type E.

Functional Interfaces, Lambdas, and Type Inference

The Key to the Magic You can create an object of interface type by creating a lambda if the interface is functional. Java performs type inference and it says, ``this lambda must be the interface's specified method.''

So when we did this

putText.setOnAction(e -> "tf.setText("Hey, look at me!"));

here is what happened.

  1. putText is a button, so it has a setOnAction method.
  2. setOnAction expects one argument, an argument of type EventHandler<ActionEvent>.
  3. EventHandler<ActionEvent> is a functional interface; it specifies one methood, void handle(ActionEvent e).
  4. Type inference occurs: An anonymous object of type EventHandler<ActionEvent> is created and its handle method is taken to be the lambda.

Magic demystified. This new style of event handling reduces the boilerplate code that adds nothing to the meaning of programs. This innovation is also great when using the new Stream API.