i have question about java function signature

Viewed 37

I found that function interface and getMethod seem to be replaceable, What makes it work?

public class App {

    public static void main(String[] args) {

        Map<String, String> collect = Stream.of(new App(), new App(), new App())
                .collect(Collectors.toMap(App::getString, (app) -> "aaa"));

    }

    public String getString() {
        return "str";
    }
}

But when I use lambda to replace getMethod, it fails . Why this does not work

        Map<String, String> collect = Stream.of(new App(), new App(), new App())
                .collect(Collectors.toMap(() -> "str", (app) -> "aaa"));
1 Answers

Collectors.toMap requires a Function<? super T, ? extends K> as its first parameter, where T is the type of elements in the stream, and K is the key type of the map you want.

In this case, you have a stream of Apps and you want a Map<String, String>, so T is App and K is String. In other words, you need a function that accepts an App, and returns a String.

App::getString is such a Function<? super T, ? extends K>. You might be wondering why it accepts a App when getString accepts no parameters. Notice how getString is an instance method, and you are referring to it without an instance! A method reference of the form ClassName::instanceMethodName implicitly accepts an extra parameter of type ClassName, because you need an instance of that class to call it!

On the other hand, your lambda is not such a function. It accepts no parameters, as indicated by the empty brackets at the start (()). Your lambda expression would be represented by the Supplier<String> functional interface, not the Function<App, String> that you need.

To use a lambda expression here, simply do what you did to the second parameter of toMap, and add a lambda parameter:

.collect(Collectors.toMap((app) -> "str", (app) -> "aaa"));
//                         ^^^

Note that this is required even if you don't use app in the lambda expression.

Related