Есть делегаты в Java 8?

есть ли делегаты в Java 8?

Если нет, то как у нас есть лямбда-выражения в JDK 8 без делегатов?

каковы способ ссылок? Они такие же, как делегаты?

2 ответов


в JDK 8 нет делегатов. Под капотом lambdas находятся экземпляры функциональных интерфейсов (интерфейс с точно одним абстрактным методом). В зависимости от того, где вы передаете свою лямбду, компилятор может выяснить, какой интерфейс он реализует. Например, коллекции.метод sort принимает экземпляр Comparator в качестве второго параметра. Компаратор является функциональным интерфейсом, поэтому компилятор проверяет, соответствует ли передаваемый лямбда абстрактному методу в Компаратор или нет.

ссылка на метод-это просто упрощение. Когда ваш лямбда-код просто вызывает существующий метод, вы можете использовать этот новый синтаксис для упрощения конструкции. Пример из связанного учебника показывает это довольно хорошо:

вместо:

Arrays.sort(rosterAsArray,
    (a, b) -> Person.compareByAge(a, b)
);

это проще со ссылкой на метод:

Arrays.sort(rosterAsArray, Person::compareByAge);

посмотрите на lambdafaq.


благодаря комментарию Pacerier по этому вопросу, вот способ выполнить то, что делает делегат C# (one-function), даже в Java 7 или ниже.

// This defines the 'delegate'.
public interface IA {
    int f(int a);
}

public class MyClass {
    // f1 and f2 have the same signature as 'IA.f'.
    private int f1(int a) {
        return a + 1;
    }

    private int f2(int a) {
        return 2 * a;
    }

    // These wrappers are one way to return a 'delegate'.
    // Each wrapper creates one instance of an anonymous class.
    // Notice that we did not have to declare MyClass as implementing IA,
    // and that we can wrap different methods of MyClass into 'IA's.
    // Contrast this with 'MyClass implements IA', which would require
    // a method 'f' in 'MyClass', and would not provide a way to
    // delegate to different methods of 'MyClass'.
    public IA wrapF1() {
        return (new IA(){
            public int f(int a) {
                return f1(a);
            }
        });
    }

    public IA wrapF2() {
        return (new IA(){
            public int f(int a) {
                return f2(a);
            }
        });
    }

    // returns a 'delegate', either to 'f1' or 'f2'.
    public IA callMe(boolean useF2) {
        if (!useF2)
            return wrapF1();
        else
            return wrapF2();
    }

}

использование

...
// Create and use three 'delegates'.
// Technically, these are not quite the same as C# delegates,
// because we have to invoke a method on each.
// That is, we must do 'ia0.f(..)' instead of 'ia0(..)'.
// Nevertheless, it satisfies the design requirement.
MyClass c = new MyClass();
IA ia0 = c.wrapF1();
IA ia1 = c.callMe(false);
IA ia2 = c.callMe(true);
int result0 = ia0.f(13);
int result1 = ia1.f(13);
int result2 = ia2.f(13);

доходность

result0: 14    <-- f1, so 13 + 1
result1: 14    <-- f1, so 13 + 1
result2: 26    <-- f2, so 2 * 13

Примечание: Если вам нужна только одна реализация для каждого класса данного "делегата", то более простым решением является прямая реализация интерфейса в классе. Вот пример. В классе уже было f3 и теперь он расширен для реализации IA:

public class MyClass2
        implements IA {
    private int baseValue;
    private int anotherValue;

    public MyClass2(int baseValue, int anotherValue) {
        this.baseValue = baseValue;
        this.anotherValue = anotherValue;
    }

    public int f3(int v1, int v2) {
        return 2 * v1 + v2;
    }

    public int f(int a) {
        return f3(baseValue + a, anotherValue);
    }
}

IA ia3 = new MyClass2(10, 3);
int result3 = ia3.f(13);   // = f3(10 + 13) = 2 * 23 + 3 = 49

в этом случае он ничем не отличается от любой другой реализации интерфейса. Дело в том, что design concept возвращает функцию, которая соответствует указанной подписи смогите быть удовлетворено, с битом дополнительного кодирвоания, используя интерфейсы Java. Во втором, более простом, случае интерфейс размещается непосредственно на классе. В первом, более общем случае, интерфейс помещается на анонимный экземпляр анонимного внутреннего класс. Для ясности и легкого доступа я изолирую этих "создателей делегатов" в функциях оболочки.

это правда, что результат не совсем такой же, как делегат C#, потому что нужно сделать ia.f(), а не ia(). Тем не менее, цель проекта была достигнута.


Примечание:Java 8, кодирование упрощается с помощью лямбд. Я не использую Java 8, поэтому я не буду включать реализацию Java 8 здесь. (Любой желающий может отправить редактирование, которое добавляет эту реализацию. Я предлагаю показать новые тела ниже для моего wrapF1() и wrapF2() выше, так как это позволит легко сравнить версии Java 7 и Java 8.)