Как компилируется приведенный ниже код с лямбда-выражениями? - PullRequest
1 голос
/ 05 мая 2019

Я читаю лямбда-пример из книги Герберта Шильдта - полный справочник по Java. Код написан на стороне файла LambdasAsArgumentsDemo.java

interface StringFunc {
String func(String n);
}

class LambdasAsArgumentsDemo {

public static void main(String args[]){
    String inStr = "Lambdas add power to Java";
    String outStr;
    // Here, a simple expression lambda that uppercases a string is passed to stringOp( ).
    outStr = stringOp((str) -> str.toUpperCase(), inStr);
    System.out.println("The string in uppercase: " + outStr);

//This method has a functional interface as the type of its
// first parameter. Thus, it can be passed a reference to
//any instance of that interface, including the instance 
//created by a lambda expression.
//The second parameter specifies the string to operate on.

        static String stringOp(StringFunc sf, String s) {
            return sf.func(s);
        }
    }

Теперь мой вопрос на линии

outStr = stringOp((str) -> str.toUpperCase(), inStr);

Почему так получается, что когда вы передаете (str) -> str.toUpperCase() в качестве аргумента, создается экземпляр функционального интерфейса StringFunc, а ссылка на этот объект передается как первый параметр stringOp() ?? Как он знает, чтобы создать экземпляр StringFunc?

1 Ответ

3 голосов
/ 05 мая 2019

StringFunc определяет интерфейс для функции, которая принимает строку в качестве аргумента и возвращает строку. Ваше лямбда-выражение (str) -> str.toUpperCase() делает то же самое. Он принимает строку ((str) и возвращает строку (str.toUppercase()), поэтому он соответствует интерфейсу.

Думайте так: нет необходимости создавать экземпляр объекта этого интерфейса, поскольку лямбда уже является экземпляром. Достаточно привести его к интерфейсу. str будет тогда именем аргумента.

Вы можете добиться того же результата, используя обычный метод с такой подписью:

public static void main(String args[]){
    String inStr = "Lambdas add power to Java";
    String outStr;
    outStr = stringOp(LambdasAsArgumentsDemo::mymethod, inStr);
    System.out.println("The string in uppercase: " + outStr);
}

public static String mymethod(String str) { return str.toUpperCase(); }
              ^                 ^                  ^
              |                 |                  implementation
              |                 String argument called str
              String return type

Из комментариев:

Кстати, у меня есть другой связанный вопрос. Что, если есть аналогичные 2 других функциональных интерфейса, например, интерфейс StringFunc2 {String func2 (String n); } и интерфейс StringFunc3 {String func3 (int n); } В таком случае, как это будет решено? Какое объяснение? Кстати, он все еще компилируется и выдает тот же вывод.

Код называет stringOp(). stringOp() занимает или StringFunc, StringFunc2 или StringFunc3. Таким образом, компилятор знает во время компиляции, какой из них выбрать.

Если, однако, вы определили три интерфейса и три функции, код не может быть скомпилирован и завершается ошибкой с сообщением об ошибке, что вызов неоднозначен, потому что лямбда может быть либо один.

import java.util.*;
import java.lang.*;
import java.io.*;

interface StringFunc {
    String func(String n);
}
interface StringFunc2 {
    String func(String n);
}
interface StringFunc3 {
    String func(String n);
}

class LambdasAsArgumentsDemo {

    public static void main(String args[]){
        String inStr = "Lambdas add power to Java";
        String outStr;
        outStr = stringOp((str) -> str.toUpperCase(), inStr);
        System.out.println("The string in uppercase: " + outStr);
    }

    static String stringOp(StringFunc sf, String s) {
        return sf.func(s);
    }

    static String stringOp(StringFunc2 sf, String s) {
        return sf.func(s)+"2";
    }

    static String stringOp(StringFunc3 sf, String s) {
        return sf.func(s)+"3";
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...