Precise definition of "functional interface" in Java 8

Recently I started exploring Java 8 and I can't quite understand the concept of "functional interface" that is essential to Java's implementation of lambda expressions. There is a pretty comprehensive guide to lambda functions in Java, but I got stuck on the chapter that gives definition to the concept of functional interfaces. The definition reads:

More precisely, a functional interface is defined as any interface that has exactly one abstract method.

An then he proceeds to examples, one of which is Comparator interface:

public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
} 

I was able to test that I can use a lambda function in place of Comparator argument and it works(i.e. Collections.sort(list, (a, b) -> a-b)).

But in the Comparator interface both compare and equals methods are abstract, which means it has two abstract methods. So how can this be working, if the definition requires an interface to have exactly one abstract method? What am I missing here?


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.


Another explanation is given in the @FunctionalInterface page:

Conceptually, 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.

You can test which interface is a correct functional interface using @FunctionalInterface.

E.g.:

  • this works

    @FunctionalInterface
    public interface FunctionalInterf {
    
        void m();
    
        boolean equals(Object o);
    
    }
    
  • this generates an error:

    @FunctionalInterface
    public interface FunctionalInterf {
    
        void m();
    
        boolean equals();
    
    }
    

    Multiple non-overriding abstract methods found in interface FunctionalInterf


Q. But in the Comparator interface both compare() and equals() methods are abstract, which means it has two abstract methods. So how can this be working, if the definition requires an interface to have exactly one abstract method? What am I missing here?

A.

A functional interface may specify any public method defined by Object, such as equals( ), without affecting its “functional interface” status. The public Object methods are considered implicit members of a functional interface because they are automatically implemented by an instance of a functional interface.


A functional interface has only one abstract method but it can have multiple default and static methods.

Since default methods are not abstract you’re free to add default methods to your functional interface as many as you like.

@FunctionalInterface
public interface MyFuctionalInterface 
{
public void perform();

default void perform1(){
//Method body
}

default void perform2(){
//Method body
}
}

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.

Comparator is a functional interface even though it declared two abstract methods. Because one of these abstract methods “equals()” which has signature equal to public method in Object class. e.g. Below interface is a valid functional interface.

@FunctionalInterface
    public interface MyFuctionalInterface 
    {
    public void perform();
 
    @Override
    public String toString();                //Overridden from Object class
 
    @Override
    public boolean equals(Object obj);        //Overridden from Object class
    }