Есть делегаты в 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.)