Зачем мне нужен функциональный интерфейс для работы с лямбдами?

Я думаю, что этот вопрос уже где-то там, но я не смог его найти.

Я не понимаю, зачем нужно иметь функциональный интерфейс для работы с лямбдами. Рассмотрим следующий пример:

public class Test {

    public static void main(String...args) {
        TestInterface i = () -> System.out.println("Hans");
//      i = (String a) -> System.out.println(a);

        i.hans();
//      i.hans("Hello");
    }
}

public interface TestInterface {
    public void hans();
//  public void hans(String a);
}

Это работает без проблем, но если вы раскомментируете прокомментированные строки, это не так. Зачем? По моему мнению, компилятор должен иметь возможность отличать оба метода, поскольку они имеют разные входные параметры. Зачем мне нужен функциональный интерфейс и взорвать мой код?

EDIT: Связанные дубликаты не ответили на мой вопрос, потому что я спрашиваю о разных параметрах метода. Но я получил некоторые действительно полезные ответы здесь, благодаря всем, кто помогал!:)

EDIT2: Извините, я, очевидно, не носитель языка, но чтобы уточнить:

public interface TestInterface {
    public void hans();                 //has no input parameters</br>
    public void hans(String a);         //has 1 input parameter, type String</br>
    public void hans(String a, int b);  //has 2 input parameters, 1. type = String, 2. type = int</br>
    public void hans(int a, int b);     //has also 2 input parameters, but not the same and a different order than `hans(String a, int a);`, so you could distinguish both
}

public class Test {

    public static void main(String...args) {
        TestInterface i = () -> System.out.println("Hans");
        i = (String a) -> System.out.println(a);
        i = (String a, int b) -> System.out.println(a + b);
        i = (int a, int b) -> System.out.println(a);

        i.hans(2, 3);   //Which method would be called? Of course the one that would take 2 integer arguments. :)
    }
}

Все, что я прошу, касается аргументов. Имя метода не имеет значения, но каждый метод принимает уникальный порядок различных аргументов, и из-за этого Oracle может реализовать эту функцию, а просто сделать единственный метод возможным для "Лямбда-интерфейса".

Ответ 1

Когда вы пишете:

TestInterface i = () -> System.out.println("Hans");

Вы даете реализацию методу void hans() TestInterface.

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

Вы не можете решить это, назначив две лямбда-выражения, имеющие разные подписи, к одной и той же переменной (так же, как вы не можете назначить ссылки двух объектов на одну переменную и ожидать, что эта переменная будет ссылаться на оба объекта одновременно).

Ответ 2

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

interface TestInterface {
    void first();
    void second(); // this is only distinguished from first() by method name
    String third(); // maybe you could say in this instance "well the return type is different"
    Object fourth(); // but a String is an Object, too !
}

void test() {
    // which method are you implementing, first or second ?
    TestInterface a = () -> System.out.println("Ido mein ado mein");
    // which method are you implementing, third or fourth ?
    TestInterface b = () -> return "Ido mein ado mein";
}

Ответ 3

Вам не нужно создавать функциональный интерфейс для создания лямбда-функции. Интерфейс позволяет создавать экземпляр для будущего вызова функции.

В вашем случае вы можете использовать уже существующий интерфейс Runable

Runnable r = () -> System.out.println("Hans");

а затем вызовите

r.run();

Вы можете думать о лямбда -> как о только короткой руке для:

Runnable r = new Runnable() {
     void run() {
          System.out.println("Hans");`
     }
}

С lambda вам не нужен анонимный класс, созданный под капотом в приведенном выше примере.

Но это имеет некоторое ограничение, чтобы выяснить, какой метод следует назвать интерфейсом, используемым с lambdas, должен быть SAM (Single Abstract Method). Тогда у нас есть только один метод.

Для более подробного объяснения читайте:

Введение в функциональные интерфейсы - концепция, воссозданная в Java 8

Ответ 4

Кажется, вы ищете анонимные классы. Работает следующий код:

public class Test {

    public static void main(String...args) {
        TestInterface i = new TestInterface() {
            public void hans() {
                System.out.println("Hans");
            }
            public void hans(String a) {
                System.out.println(a);
            }
        };

        i.hans();
        i.hans("Hello");
    }
}

public interface TestInterface {
    public void hans();
    public void hans(String a);
}

Лямбда-выражения (в основном) - это более короткий способ писать анонимные классы только с одним методом. (Подобным образом, анонимные классы являются сокращенными для внутренних классов, которые вы используете только в одном месте)