Search code examples
javajava-8overloadingfunctional-interface

Is there a way to overload an abstract method in a functional interface?


I would like to be able to provide a functional interface that accepts several different types of lambda functions.

I read this. The first answer to this question clarifies why overloading an abstract method in a functional interface could cause undefined behavior. However, is there a way to do the equivalent of overloading an abstract method in a functional interface if I supply all of the defaults?

I would like to be able to write something like the following code:

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

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

The desired result would be:

You hit it!
default false
default hit
false

Consider the following (non-compilable) code (mostly copied from the linked question):

@FunctionalInterface
public interface Ball
{
    void hit();
    void hit(boolean miss);
    default void hit(){
        System.out.println("default hit");
    }
    default void hit(boolean miss){
        System.out.println("default" + miss);
    }

}

I am looking for an alternative to this code that would compile.


Solution

  • You could wrap the interface in a class and then pass on the method calls to the interfaces internally.

    Example code:

    public class Test{
        public static void main(String... args) throws Exception{
            Ball b = new Ball(() -> System.out.println("You hit it!"));
            Ball ba = new Ball((boolean miss) -> System.out.println(miss));
    
            b.hit();
            b.hit(false);
            ba.hit();
            ba.hit(false);
        }
    
        public static class Ball{
            final Hit a;
            final HitBoolean b;
            
            public Ball(Hit a){
                this.a = a;
                b = (miss) -> System.out.println("default " + miss);
            }
            
            public Ball(HitBoolean b){
                this.b = b;
                a = () -> System.out.println("default hit");
            }
            
            public void hit(){
                a.hit();
            }
            
            public void hit(boolean miss){
                b.hit(miss);
            }
        }
    
        public interface Hit{
            void hit();
        }
        
        public interface HitBoolean{
            void hit(boolean miss);
        }
    }
    

    Output of the program:

    You hit it!
    default false
    default hit
    false