Precise Definition of "Functional Interface" in Java 8

Precise definition of functional interface in Java 8

From the same page you linked to:

The interface Comparator is functional because although it declares two abstract methods, one of these—equals— has a signature corresponding to a public method in Object. Interfaces always declare abstract methods corresponding to the public methods of Object, but they usually do so implicitly. Whether implicitly or explicitly declared, such methods are excluded from the count.

I can't really say it better.

Definition of Functional Interface in Java 8

It is true that the Comparator interface has 2 abstract methods. But one of them is equals, which overrides the equals method defined in the Object class, and this method doesn't count.

From @FunctionalInterface:

If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

As such, this makes the Comparator interface a functional interface where the functional method is compare(o1, o2).

The lambda expression (a, b) -> a > b ? -1 : 1 complies with that contract: it declares 2 parameters and return an int.

Purpose of Functional Interfaces in Java8

Obviously you can skip using these new interfaces and roll your own with better names. There are some considerations though:

  1. You will not be able to use custom interface in some other JDK API unless your custom interface extends one of built-ins.
  2. If you always roll with your own, at some point you will come across a case where you can't think of a good name. For example, I'd argue that CheckPerson isn't really a good name for its purpose, although that's subjective.

Most builtin interfaces also define some other API. For example, Predicate defines or(Predicate), and(Predicate) and negate().

Function defines andThen(Function) and compose(Function), etc.

It's not particularly exciting, until it is: using methods other than abstract ones on functions allows for easier composition, strategy selections and many more, such as (using style suggested in this article):

Before:

class PersonPredicate {
public Predicate<Person> isAdultMale() {
return p ->
p.getAge() > ADULT
&& p.getSex() == SexEnum.MALE;
}
}

Might just become this, which is more reusable in the end:

class PersonPredicate {
public Predicate<Person> isAdultMale() {
return isAdult().and(isMale());
}

publci Predicate<Person> isAdultFemale() {
return isAdult().and(isFemale());
}

public Predicate<Person> isAdult() {
return p -> p.getAge() > ADULT;
}

public Predicate<Person> isMale() {
return isSex(SexEnum.MALE);
}
public Predicate<Person> isFemale() {
return isSex(SexEnum.FEMALE);
}
public Predicate<Person> isSex(SexEnum sex) {
return p -> p.getSex() == sex;
}
}

What are functional interfaces used for in Java 8?

@FunctionalInterface annotation is useful for compilation time checking of your code. You cannot have more than one method besides static, default and abstract methods that override methods in Object in your @FunctionalInterface or any other interface used as a functional interface.

But you can use lambdas without this annotation as well as you can override methods without @Override annotation.

From docs

a functional interface has exactly one abstract method. Since default
methods have an implementation, they are not abstract. If an interface
declares an abstract method overriding one of the public methods of
java.lang.Object, that also does not count toward the interface's
abstract method count since any implementation of the interface will
have an implementation from java.lang.Object or elsewhere

This can be used in lambda expression:

public interface Foo {
public void doSomething();
}

This cannot be used in lambda expression:

public interface Foo {
public void doSomething();
public void doSomethingElse();
}

But this will give compilation error:

@FunctionalInterface
public interface Foo {
public void doSomething();
public void doSomethingElse();
}

Invalid '@FunctionalInterface' annotation; Foo is not a functional
interface

How to determine if the interface is functional in Java?

From the JLS §9.8 (highlighting mine):

A functional interface is an interface that has just one abstract method (aside from the methods of Object)

The rationale is

  1. to use the interface, you have to instantiate it. Every instantiation necessarily inherits from Object, and thus implements these abstract methods anyway.

    The other method - boolean equals(Object) - is an explicit declaration of an abstract method that would otherwise be implicitly declared, and will be automatically implemented by every class that implements the interface.

  2. As a functional interface, it is very unlikely that you want to call a method that is defined by Object. Thus, these methods do not count when searching for a method to call (because the method of functional interfaces can be called without naming that method).

    This is to allow functional treatment of an interface like java.util.Comparator<T> that declares multiple abstract methods of which only one is really "new" - int compare(T,T).

Should 'ComparableT' be a 'Functional interface'?

A lambda expression can be used where an instance of an interface with a single abstract method is required. You wrote,

Simply because an interface happens to have single abstract method, it should not be considered as a functional interface.

This is exactly correct. Having a single abstract method is a structural property of an interface, one that makes it eligible to be implemented with a lambda. However, whether an interface makes sense or is semantically sensible to be implemented with lambda is a different story. The latter is the purpose of the @FunctionalInterface annotation. When it is present on an interface, it indicates the intent that the interface is useful to be implemented with a lambda.

Notably, the Comparable interface lacks the @FunctionalInterface annotation.

While it's probably nonsensical to use a lambda as a Comparable implementation, there doesn't seem to be any reason to create a mechanism to prevent this from being done. It doesn't seem like doing this would be a source of error, which would be a good reason to develop such a mechanism. By contrast, the @FunctionalInterface annotation is intended to guide programmers in the right direction instead of prohibiting something that is arguably wrong but doesn't seem truly harmful.

Functional Interface vs Interfaces with single methods like Runnable

There is no difference, the docs for FunctionalInterface state:

An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface [emphasis added]

and

However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a FunctionalInterface annotation is present on the interface declaration.

So the annotation is only there to indicate that the developer intended the interface to be used as a functional interface.



Related Topics



Leave a reply



Submit