Why Functional Interfaces in Java 8 Have One Abstract Method

Why not multiple abstract methods in Functional Interface in Java8?

Writing Lamba expression meaning we are implementing the interface that is functional interface. It should have one abstract method because at the time of lambda expression, we can provide only one implementation at once.
So in the code snippet posted in the question, at any time we are giving only one implementation while declaring Lambda where we will have to implement for two abstract methods.

Thanks for the help.

Every interface with a single abstract method should be a functional interface?

Explanation

Every interface that only offers one (abstract) method, i.e. without implementation, is a so called functional interface.

Being it explicitly or implicitly.

The annotation @FunctionalInterface is, like @Override, optional, if you want to create a functional interface.

So if you declare an interface @FunctionalInterface, but it actually has more than just one such method, the compiler helps you and prevents compilation with an error. Telling you that you violated your own intention.

If you do not have the annotation, it will compile, but it is not a functional interface anymore. This could be a bug to you, because your intention was to create a functional interface. Note that if you are actually using the interface in an environment where a functional interface is actually required, like for a lambda, it would obviously not compile anymore as soon as another method is added to the interface.

Here are some examples:

// is a functional interface
interface Foo {
void bar();
}

// is a functional interface
@FunctionalInterface
interface Foo {
void bar();
}

// is not a functional interface
interface Foo {
void bar();
void baz();
}

// does not compile
@FunctionalInterface
interface Foo {
void bar();
void baz();
}


Use

It is to make your intention clear to the compiler, other team members and your future self. That way, the compiler can help you spot bugs in case you mess up.

Another scenario might be if you are working in a team and design an interface. If you do not clearly mark this interface as functional interface, either by the annotation or with a comment/documentation, another team member might not know your intention and add more methods to it.

This is especially important if you are a library designer, i.e. writing code that is to be used by other, external, people. If you mark your interface @FunctionalInterface, it is a promise to them that you intent to keep it like that. So they can safely use it for lambdas, for example. Without fearing that their code will break as soon as you ship an update to your library.

The opposite case is true as well. If they spot an interface of yours that only has one method, but is not explicitly annotated, they will understand that this is not meant to be used as functional interface, eventhough it currently is one. Thus, they will not use it for lambdas, although they could, since you might change it in a future update.



Details

You can read about the precise definitions in JLS§9.8. Functional Interfaces:

A functional interface is an interface that has just one abstract method (aside from the methods of Object), and thus represents a single function contract. This "single" method may take the form of multiple abstract methods with override-equivalent signatures inherited from superinterfaces; in this case, the inherited methods logically represent a single method.

And JLS§9.6.4.9. @FunctionalInterface:

The annotation type FunctionalInterface is used to indicate that an interface is meant to be a functional interface (§9.8). It facilitates early detection of inappropriate method declarations appearing in or inherited by an interface that is meant to be functional.

It is a compile-time error if an interface declaration is annotated with @FunctionalInterface but is not, in fact, a functional interface.

Because some interfaces are functional incidentally, it is not necessary or desirable that all declarations of functional interfaces be annotated with @FunctionalInterface.

The last paragraph here is especially important. I.e. you might have created a functional interface incidentally and plan to add more to it later. So people should not mistake this and use it with lambdas, otherwise their code will break later, when you add more methods.



Note

As mentioned before, the @Override tag works the same, but for overriding methods. So you can also override methods without it. But if you use it and maybe made a typo, i.e. you are not actually overriding something, the compiler will help you spot this issue immediately.

When we add two abstract methods in an interface and implement just one method then why can't we implement the other method using lambda?

You can create a sub-interface of MyInterface with all but one methods implemented using the default keyword. It allows you to provide default implementations that interface implementers "inherit" if they do not provide own implementations. Thus methods with default implementation are not abstract anymore. If you default-implement all but one interface in s sub-interface effectively you end up with a functional interface (a single abstract method interface). And this allows you to use lambda expressions.

interface PartialInterface extends MyInterface {
@Override
default void func() {
System.out.println("func");
}
}
class Lambda {
public void doWork(PartialInterface myInterface) {
// both methods from the interface can be used
myInterface.func(); // the default implementation "inherited" from PartialInterface
myInterface.func(42); // the single abstract method (inherited by PartialInterface from myInterface) overridden by the lambda expression
}

public static void main(String[] args) {
Lambda lambda = new Lambda();
lambda.doWork(e -> System.out.println("func:" + e));
}
}

Is the purpose of `abstract` keyword in a FunctionalInterface to distinguish the 'lambda' method from other abstract methods?

Although you can use abstract in an interface, it has no extra meaning, as all methods in an interface (except default, private or static methods) are by definition abstract. It has no extra meaning in a functional interface, and if you annotate your interface with @FunctionalInterface, both of your examples with two methods will fail to compile as they are equivalent.

To be complete, your first example does have an abstract method, and is a potential function interface. Your second and third example both have two abstract methods, and cannot be used as a function interface.

See also the Java Language Specification 17, section 9.4:

An interface method lacking a private, default, or static
modifier is implicitly abstract. Its body is represented by a
semicolon, not a block. It is permitted, but discouraged as a matter
of style, to redundantly specify the abstract modifier for such a
method declaration.

(emphasis mine)

and section 9.8:

A functional interface is an interface that is not declared sealed
and has just one abstract method (aside from the methods of
Object), and thus represents a single function contract.

Why can't we overload a abstract method in a functional interface? (Java)

In languages without method overloading, methods are uniquely identified by their name in that class (ignoring overriding for the moment).

In Java things are a little different though. Citing from the oracle docs:

Overloading Methods

The Java programming language supports overloading methods, and Java can distinguish between methods with different method signatures. This means that methods within a class can have the same name if they have different parameter lists (there are some qualifications to this that will be discussed in the lesson titled "Interfaces and Inheritance").

So we know that methods are also identified by their signature. If two methods share a name but don't have the same signature, they are different methods. Don't let their shared name fool you into thinking that they are somehow related.

Considering this fact, we can easily create an example in which undefined behavior would occur if methods behaved the way you described:

Ball ba = (boolean miss) -> System.out.println(miss);
someFunction(ba)
public void someFunction(Ball ball) {
ball.hit();
}

What behavior would you expect in this case? It is undefined!


You can — however — make use of default methods. I don't know your situation well enough to judge if this is a suitable approach, but you can do this:

@FunctionalInterface
public interface Ball
{
default void hit() {
hit(true);
}

void hit(boolean miss);
}

Why this works is explained in the documentation for FunctionalInterface:

Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract

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.

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

Can @FunctionalInterfaces have default methods?

You can have default methods in a functional interface but its contract requires you to provide one single abstract method (or SAM). Since a default method have an implementation, it's not abstract.

Conceptually, a functional interface has exactly one abstract method.
Since default methods have an implementation, they are not abstract.

and

If a type is annotated with this annotation type, compilers are
required to generate an error message unless:

The type is an interface type and not an annotation type, enum, or
class.

The annotated type satisfies the requirements of a functional
interface.

Here you don't satisfy the functional interface's requirement, so you need to provide one abstract method. For example:

@FunctionalInterface
interface MyInterface {

boolean authorize(int val);

default boolean authorize(String value) {
return true;
}
}

Note that if you declare an abstract method overriding one of a public method from the Object's class it doesn't count, because any implementation of this interface will have an implementation of those methods through at least the Object's class. For example:

@FunctionalInterface
interface MyInterface {

default boolean authorize(String value) {
return true;
}

boolean equals(Object o);
}

does not compile.



Related Topics



Leave a reply



Submit