Function interface as function reference

226 views Asked by At
public static void main(String o[]) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("a", 1);
    map.entrySet().stream().sorted(Comparator.comparing(Entry::getValue)).forEach(System.out::println);
}

Above code builds and runs perfectly but it shouldn't. Comparator.comparing takes a function reference and only those methods which takes one argument and returns one argument can be mapped on this. But in above code getValue is mapped and works fine but it doesn't take any parameter. Code should give build issue but doesn't. Is there any issue with my concept?

2

There are 2 answers

2
Eran On BEST ANSWER

The single argument comparing method:

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor)

takes a Function<? super T, ? extends U> argument, which is a functional interface that contains a single method that takes a argument of one type and returns a value of some other type.

Entry::getValue takes an argument of one type (Map.Entry<String, Integer> in your example) and returns a value of some other type (Integer in your example). Therefore it matches the Function functional interface.

But in above code getValue is mapped and works fine but it doesn't take any parameter.

Yes it does - each Map.Entry element taken from the Stream serves as an argument of the apply() method of the Function interface.

Perhaps this will clarify:

Function<Map.Entry<Integer, String>, String> func = Map.Entry::getValue;

The getValue() method of Map.Entry can be viewed as a Function that accepts a Map.Entry instance and return the value of that instance (returned by calling getValue() on that instance).

4
jrtapsell On

In this case, your method reference is an instance method, rather than a static one, so instead of for each item calling and using the value of:

Entry.getValue(item)

It uses

item.getValue() [JavaDoc] (https://docs.oracle.com/javase/7/docs/api/java/util/Map.Entry.html#getValue())

so it acts as the lambda: p -> p.getValue(), converting an entry into its value for comparison, as it has one argument and returns one value without throwing exceptions it can implement Function<Entry<String, Integer>, Integer>.

If both a static and instance method exists you cannot use a method reference, as per this question: Link

Worked example