8

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?

Neuron
  • 5,141
  • 5
  • 38
  • 59
HomeworkHopper
  • 300
  • 1
  • 12
  • 4
    Because if you do, there is now **two** abstract methods, and a functional interface must have **exactly one** abstract method. Overloaded methods are entirely distinct from each other, they just happen to share a name. – Andreas Feb 28 '19 at 01:14
  • Right, but as long as those two methods have different parameters, I do not see why they can't be distinguished and therefore keep the interface functional. – HomeworkHopper Feb 28 '19 at 01:15
  • 1
    They *can* be distinguished. They *are* distinct. Hence they are *different*. Not the same. So more than one, violating the "exactly one" requirement of a functional interface. – Andreas Feb 28 '19 at 01:17
  • 2
    Two overloaded methods require two method bodies (implementations). A functional interface must be an interface that can be *fully* implemented with a **single** method body, which can then be implemented using Lambda syntax or Method Reference syntax. – Andreas Feb 28 '19 at 01:19
  • I suppose I'm questioning that "exactly one" rule then.... it makes sense in the case of there being two methods with different names that both take the same parameters - in that case the compiler would not be able to tell which one you are trying to reference from the lambda, but two methods of the same name which take different parameters are distinguishable. – HomeworkHopper Feb 28 '19 at 01:19
  • 1
    *"which one you are trying to reference from the lambda"*. You are entirely missing the point. It's not about *using* (aka referencing) the interface. It's about *implementing* the interface. See my [previous comment](https://stackoverflow.com/questions/54916914/why-cant-we-overload-a-method-in-a-functional-interface-java#comment96599975_54916914). – Andreas Feb 28 '19 at 01:21
  • 1
    @Andreas - Oh my God. You're right, I guess I sort of forgot what lambda expressions are actually doing – HomeworkHopper Feb 28 '19 at 01:30

2 Answers2

4

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

Community
  • 1
  • 1
Neuron
  • 5,141
  • 5
  • 38
  • 59
  • Yep. That makes sense. I wasn't thinking about all of the contexts in which functional interfaces and lambda expressions can be used. – HomeworkHopper Feb 28 '19 at 01:35
  • @Cyber_Agent glad to hear that. I added an interesting option to the end of my answer which might help you out – Neuron Feb 28 '19 at 01:42
  • 1
    Oohh, I never would have thought of that approach. That actually DOES achieve the behavior I was imagining. Thank you! – HomeworkHopper Feb 28 '19 at 01:47
2

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.

ChenZhou
  • 102
  • 9