Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

So I am familiar with functional interfaces in java, and their use with lambda expressions. A functional interface can only contain one abstract method. When using this lonely method from a lambda expression, you do not need to specify its name - since there is only one abstract method in the interface, the compiler knows that's the method you are referencing.

Example:

// Functional Interface:

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

// Lambda to define, then run the hit method:

Ball b = () -> System.out.println("You hit it!");

b.hit();

Although it is obvious why a functional interface can only contain one abstract method, I do not understand why it is not possible to overload that method.

For example, the following will not compile:

// (NOT) Functional Interface:

@FunctionalInterface
public interface Ball
{
    void hit();
    void hit(boolean miss);
}

// Lambda to define, then run the hit method:

Ball b = () -> System.out.println("You hit it!");
Ball ba = (boolean miss) -> System.out.println(miss);

b.hit();
ba.hit(false);

The compiler states that the Ball interface is not functional because it contains more than one method, but in this case I do not understand why this would be a problem - As long as the two methods take different parameters, it should be possible to infer which method I'm referencing in the lambda based on what parameters I define.

Can someone explain why it is not possible to overload a abstract method within a functional interface?

like image 768
HomeworkHopper Avatar asked Feb 28 '19 01:02

HomeworkHopper


2 Answers

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

like image 163
Neuron Avatar answered Sep 23 '22 03:09

Neuron


As long as you are declairing a class which implements Ball interface,you must implements all the abstract methods. For example,if you do it like this:

Ball b = () -> System.out.println("You hit it!");

then you pass b as a parameter,and other code call b.hit(true),it will crush,because hit(boolean miss) is not implemented.

So a functional interface must only have one abstract method.

like image 31
ChenZhou Avatar answered Sep 24 '22 03:09

ChenZhou