1

A class implements a functional interface. This class has multiple methods with similar signatures, ie. they have an empty parameter list. A method that accepts this functional interface as an argument will accept any of those methods, even though they are not defined in the interface.

public class Frogs {
    public static void main(String[] args) {
        Froggo frog = new Froggo();
        moveTheFrog(frog::move);
        moveTheFrog(frog::jump);
        moveTheFrog(frog::swim);
        moveTheFrog(frog::croak);
        }
    static void moveTheFrog(Froginetic froginetic) {
        froginetic.move();
        }
    @FunctionalInterface
    interface Froginetic {
        void move();
        }
    static class Froggo implements Froginetic {
        @Override
        public void move() { System.out.println("move"); }
        void swim() { System.out.println("swim"); }
        void jump() { System.out.println("jump"); }
        void croak() { 
            System.out.println("croak"); 
            System.exit(2460); // bucks}
            }
        }
    }

Can't the compiler see that frog::jump is not defined in Froginetics? The designer of the moveTheFrog method would definitely not expect, nor account for, the effects of frog::croak.

It looks like good old fashioned C function ptrs are now a part of Java.

Is this broke? Or is this by design?

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724

1 Answers1

0

As we know from the Java tutorials

moveTheFrog(frog::move);

is more or less equivalent to

moveTheFrog(() -> from.move());

Because the target type of the argument is a functional interface, the body of the lambda expression becomes the body of the interface method. Similarly for method references, the body of the interface method becomes the body of the referenced method.

This is a feature of the language and doesn't have anything to do with the method being defined in one class or another. It's about compatibility between method signatures.

Froginetic doesn't know anything about Froggo.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • All true. However, when froginetic.move() is executed, its not necessarily executing Froggo.move(). Its executing any one of the matching methods in the Froggo class. If I see code that reads froginetic.move(), I'd expect that the interface implementation in Froggo, that is Froggo.move(), would be executed. It ain't necessarily gonna happen. Any of the other methods in Froggo might be run. – Jerry Campbell Apr 08 '14 at 02:40
  • @JerryCampbell That's the thing. You aren't passing a `Froggo` object to the `Frogs.moveTheFrog()` method. In this case, you're passing a lambda proxy that has some implementation. – Sotirios Delimanolis Apr 08 '14 at 02:41
  • I understand whats happening, er how it works. It just doesn't seem like a tight design. If the coder specifically identifies something by name, the specificity should be honored. – Jerry Campbell Apr 08 '14 at 02:54
  • @Jerry Right, the specification here says that `Frog#croak` has a signature compatible with `Froginetic#move()` and therefore a method reference to it can be used. This is just one example. I could create my own `public void randomlyNamedMethod()` that would also fit the bill. It has nothing to do with the name of the method. – Sotirios Delimanolis Apr 08 '14 at 02:59
  • @JerryCampbell Maybe [this related question](http://stackoverflow.com/questions/22561614/java-8-streams-min-and-max-why-does-this-compile) will help. – Sotirios Delimanolis Apr 08 '14 at 02:59
  • Thats not just new in java 8... thats java. Type Erasure is still a factor. Jump is not defined on Froginetic, java doesn't know that jump exists. – AnthonyJClink Apr 08 '14 at 03:00