0

I have come across a use of Java Method Reference which I don't know how it can be compiled and executed successfully.

I have the following @FunctionalInterface:

@FunctionalInterface
public interface NotifyFunction {
    void notify(NotifyService notifyService, String message, int target);
}

The NotifyService is an interface which has some methods:

public interface NotifyService  {
    public void notifyOne(String message, int target);
    public void notifyTwo(String message, int target);
}

public class ConsoleNotifyService implements NotifyService {

    public void notifyOne(String message, int target) {
        System.out.println("[ONE] " + message + target);
    }
    
    public void notifyTwo(String message, int target) {
        System.out.println("[TWO] " + message + target);
    }
}

I add an enum for containing all the strategies:

public enum NotifyStrategy {

    // HOW???
    ONE(NotifyService::notifyOne),
    TWO(NotifyService::notifyTwo);
    
    private final NotifyFunction notifyFunction;
    
    NotifyStrategy(NotifyFunction notifyFunction) {
        this.notifyFunction = notifyFunction;
    }
    
    public void notify(NotifyService notifyService) {
        this.notifyFunction.notify(notifyService, "TEST", new java.util.Random().nextInt());
    }
}

I don't understand how Java can convert from NotifyService::notifyOne to an instance of NotifyFunction when:

(1) The method signatures do not match. (2) NotifyService::notifyOne is a reference to an interface.

The following main works correctly:

public static void main(String... args) {
    NotifyStrategy.ONE.notify(new ConsoleNotifyService());
    NotifyStrategy.TWO.notify(new ConsoleNotifyService());
}
Genzer
  • 2,921
  • 2
  • 25
  • 38

1 Answers1

0

According to the JLS

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.

NotifyFunction defines only one abstract method thus it is a valid functional interface.

And every functional interface could be implemented either by using lambda expression or with a method reference.

I don't understand how Java can convert from NotifyService::notifyOne to an instance of NotifyFunction

There's no such conversion. NotifyFunction is implemented with reference to the instance method NotifyService

This type of method reference is classified as

reference to an instance method of an arbitrary object of a particular type

If you are perplexed by the usage of interface in the method reference, here is another example:

BiFunction<Collection<Integer>, Integer, Boolean> func =
                Collection::add;

This function expects a collection (any collection) and an item to add. Instance method add() will be invoked on an arbitrary collection passed to that function, not on the Collection interface.

The method signatures do not match.

We have the following method signatures for the abstract method of the NotifyFunction and method notifyOne() defined by the NotifyService:

notify(NotifyService notifyService, String message, int target)
notifyOne(String message, int target)

I.e. that we can implement NotifyFunction with lambda expression like that:

(notifyService, message, target) -> notifyService.notifyOne(message, target)

Which boils down to a method reference NotifyService::notifyOne.

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46