Целта на ламбда изразите е да означават методи, които Patch
-обектът може да извика (обратно) при определени събития. За разлика от други езици за програмиране не беше възможно да се предават функции като параметри на конструктори или методи в Java. По този начин беше необходимо да се създаде обект от клас, който имплементира определен интерфейс (или по друг начин е известно, че има определен метод по тип) и да се предаде на метода или конструктора като параметър. След това методът може да бъде извикан при предавания обект, когато се случи събитието.
Функционалният интерфейс вече е там. Не е необходимо да го създавате сами. Той вече е бил използван в сигнатурата на конструктора на Patch
(типовете на последните три параметъра на конструктора). Функционалните интерфейси са типове, които имат точно един абстрактен метод, който трябва да бъде заменен.
Да предположим, че функционалният интерфейс изглежда така:
interface Callback { // could of course have a different name
public void call(JSONObject o);
}
Не е необходимо да добавяте @FunctionalInterface
-анотацията. Това само ще предотврати по-късни модификации на интерфейса, а именно добавяне на допълнителни абстрактни методи.
Изглежда разумно да се предположи, че абстрактният метод няма върната стойност (но трябва да проверите това. Когато използвате ламбда изрази, не е нужно да знаете какво е действителното име на метода (тук call
).
Въпреки че е най-удобно, не е необходимо да извиквате конструктора с ламбда изрази за последните три параметъра. Други възможности включват препратка към метод (използвайки ::), анонимни класове и инстанциране на новодефиниран клас.
Разбира се, трябва да знаете какво трябва да се случи, когато се случат трите събития. Да кажем, че вече имате три метода, които осигуряват необходимата функционалност. Вероятно JSONObject
, който съдържа информация за събитието, е необходим, за да се направи нещо полезно.
class Main {
static void onDiscovery(JSONObject o) {...}
static void onData(JSONObject o) {...}
static void onStatus(JSONObject o) {...}
}
Не е необходимо трите метода да имат точно тези имена, нито да са static
.
В метода main
на този клас (или някъде другаде) може да се случи:
public static void main(String[] args) {
JSONObject o = // ...
Patch p = new Patch(o,
(x) -> Main.onDiscovery(x), // (1) lambda expr. (Main. can be omitted)
Main::onData, // (2) method reference
new Callback() { // (3) anonymous inner class
public void call(JSONObject x) {
Main.onStatus(x);
}
});
//...
}
(1)-(3) показват алтернативни начини за предаване на обект от тип Callback
.
(1) има предимството, че по-кратките имплементации могат да отидат точно тук, вместо да извикват onDiscovery(x)
. Ако имате повече от един израз, имате нужда от къдрави скоби около изразите и ; след всяко изявление:
(x) -> {
System.out.println("discovery event");
System.out.println(x.getXYZ());
// ...
}
(2) има предимството да бъде супер сбит. Ако нямате статичен метод за препратка, препратка към обект може също да се използва за обозначаване на обекта, на който методът трябва да бъде извикан.
(3) анонимните вътрешни класове обикновено няма да се използват повече за функционални интерфейси. Ако интерфейсът / абстрактният клас има повече абстрактни методи, но един, все още е необходимо да се използват анонимни вътрешни класове.
class Main {
void onData(JSONObject o) { ... }
// ...
public static void main(String[] args) {
var m = new Main();
var o = new JSONObject(); // or whatever
var p = new Patch(o,
(x) -> m.onDiscovery(x),
m::onData;
new Callback() {
public void call(JSONObject x) {
m.onStatus(x);
}
});
}
}
person
tastaturtier
schedule
08.07.2020