W Javie 8 natknąłem się na nowy termin: „interfejs funkcjonalny”. Podczas pracy z wyrażeniami lambda mogłem znaleźć tylko jedno jego użycie .
Java 8 zapewnia wbudowane interfejsy funkcjonalne i jeśli chcemy zdefiniować dowolny interfejs funkcjonalny, możemy skorzystać z @FunctionalInterface
adnotacji. Pozwoli nam to zadeklarować tylko jedną metodę w interfejsie.
Na przykład:
@FunctionalInterface
interface MathOperation {
int operation(int a, int b);
}
Jak przydatne jest to w Javie 8 poza samą pracą z wyrażeniami lambda ?
(Pytanie tutaj różni się od tego, które zadałem. Chodzi o pytanie, dlaczego potrzebujemy interfejsów funkcjonalnych podczas pracy z wyrażeniami lambda. Moje pytanie brzmi: dlaczego interfejsy funkcjonalne mają inne zastosowania oprócz wyrażeń lambda?)
Odpowiedzi:
@FunctionalInterface
adnotacja jest przydatna do sprawdzania czasu kompilacji kodu. Nie można mieć więcej niż jedną metodę opróczstatic
,default
i metody abstrakcyjne, że metody nadpisywania wObject
na swój@FunctionalInterface
lub inny interfejs wykorzystywany jako interfejs funkcjonalnej.Ale możesz używać lambd bez tej adnotacji, a także możesz przesłonić metody bez
@Override
adnotacji.Z dokumentów
To mogą być stosowane do ekspresji lambda:
Nie można tego użyć w wyrażeniu lambda:
Ale to da błąd kompilacji :
źródło
java.lang.Object
funkcjonalnym interfejsie.public
metody opróczstatic
idefault
”…Dokumentacja sprawia, że rzeczywiście różnicy między celów
i przypadek użycia
którego sformułowanie nie wyklucza ogólnie innych przypadków użycia. Ponieważ głównym celem jest wskazanie funkcjonalnego interfejsu , twoje pytanie sprowadza się do „Czy istnieją inne przypadki użycia interfejsów funkcjonalnych inne niż wyrażenia lambda i odwołania do metod / konstruktorów?”
Ponieważ interfejs funkcjonalny jest konstrukcją języka Java zdefiniowaną w specyfikacji języka Java, tylko ta specyfikacja może odpowiedzieć na to pytanie:
JLS §9.8. Funkcjonalne interfejsy :
Zatem specyfikacja języka Java nie mówi inaczej, jedyny przypadek użycia wspomniany w tej sekcji to tworzenie instancji interfejsu z wyrażeniami odwołań do metod i wyrażeniami lambda. (Obejmuje to odniesienia do konstruktorów, ponieważ są one wymienione jako jedna z form wyrażenia odwołania do metody w specyfikacji).
Więc jednym zdaniem nie, nie ma innego przypadku użycia tego w Javie 8.
źródło
public static String generateTaskId()
a co by było bardziej „funkcjonalne”, ktoś inny zdecydował się napisać to tak, jakpublic class TaskIdSupplier implements Supplier<String>
w przypadkuget
metody wykorzystującej wdrożenie istniejącej generacji. Czy to niewłaściwe użycie funkcjonalnych interfejsów, zwłaszcza ponowne użycieSupplier
wbudowanego JDK? PS: Nie mogłem znaleźć lepszego miejsca / pytań i odpowiedzi, aby o to zapytać. Chętnie przeprowadzę migrację, jeśli możesz to zasugerować.TaskIdSupplier
. Teraz pytanie brzmi, dlaczego utworzyłeś nazwaną klasę. Istnieją scenariusze, w których taki nazwany typ jest potrzebny, np. Gdy chcesz wspierać znajdowanie implementacji za pośrednictwemServiceLoader
. Nie ma nic złego w pozwoleniu mu na wdrożenieSupplier
. Ale kiedy tego nie potrzebujesz, nie twórz tego. Gdy potrzebujesz tylko aSupplier<String>
, już wystarczy użyćDeclaringClass::generateTaskId
i wyeliminować potrzebę jawnej klasy, co jest celem tej funkcji języka.TaskIdSupplier
implementacja jest warta wysiłku, ale wtedy pomysłServiceLoader
totalnie zapomniał. Napotkał na kilka pytań w trakcie tych dyskusji byliśmy mających takie jak Co jest zastosowanieSupplier
„spublic
istnienia, kiedy można iść do przodu i rozwijać własne interfejsy? i dlaczego nie miećpublic static Supplier<String> TASK_ID_SUPPLIER = () ->...
jako globalnej stałej? . (1/2)variable.genericMethodName(args)
zamiastmeaningfulMethodName(args)
. Używanie typu klasy do reprezentowania funkcji, czy to za pośrednictwem wyrażenia lambda / odwołania do metody, czy ręcznie utworzonej klasy, jest jedynie narzędziem do przekazywania funkcji (w przypadku braku prawdziwych typów funkcji w Javie). Należy to robić tylko w razie potrzeby.Jak powiedzieli inni, interfejs funkcjonalny to interfejs, który ujawnia jedną metodę. Może mieć więcej niż jedną metodę, ale wszystkie inne muszą mieć domyślną implementację. Powodem, dla którego nazywa się go „interfejsem funkcjonalnym”, jest fakt, że skutecznie działa jako funkcja. Ponieważ jako parametry można przekazywać interfejsy, oznacza to, że funkcje są teraz „obywatelami pierwszej klasy”, jak w funkcjonalnych językach programowania. Ma to wiele zalet, a zobaczysz je dość często podczas korzystania z interfejsu Stream API. Oczywiście wyrażenia lambda są ich głównym oczywistym zastosowaniem.
źródło
Ani trochę. Wyrażenia lambda są jedynym punktem tej adnotacji.
źródło
@Override
do tego, aby dać znać kompilatorowi, że zamierzałeś napisać coś, co było „funkcjonalne” (i otrzymać błąd, jeśli się poślizgniesz).Wyrażenie lambda można przypisać do typu interfejsu funkcjonalnego, ale także odwołania do metod i klasy anonimowe.
Jedną miłą rzeczą specyficznych interfejsów funkcjonalnych w
java.util.function
to, że mogą one składać się stworzyć nowe funkcje (jakFunction.andThen
iFunction.compose
,Predicate.and
itp) ze względu na poręczne metod domyślnych, które zawierają.źródło
Interfejs z tylko jedną abstrakcyjną metodą nazywany jest interfejsem funkcjonalnym. Korzystanie z @FunctionalInterface nie jest obowiązkowe, ale najlepiej jest używać go z interfejsami funkcjonalnymi, aby uniknąć przypadkowego dodania dodatkowych metod. Jeśli interfejs jest oznaczony adnotacją @FunctionalInterface i próbujemy mieć więcej niż jedną metodę abstrakcyjną, zgłasza błąd kompilatora.
źródło
Interfejs funkcjonalny:
Przykład 1:
Przykład 2:
Przykład 3:
Adnotacja Java8 -
@FunctionalInterface
Zastosowania interfejsu funkcjonalnego:
Aby nauczyć się interfejsów funkcjonalnych, nauczyć się pierwszych metod domyślnych w interfejsie, a po nauczeniu się interfejsu funkcjonalnego będzie Ci łatwo zrozumieć odniesienie do metody i wyrażenie lambda
źródło
Możesz użyć lambdy w Javie 8
Więcej informacji na temat Java Lambdas i FunctionalInterfaces
źródło
@FunctionalInterface
to nowa adnotacja, która została wydana wraz z Javą 8 i zawiera typy docelowe dla wyrażeń lambda i jest używana do sprawdzania czasu kompilacji kodu.Kiedy chcesz go użyć:
1- Twój interfejs nie może mieć więcej niż jednej metody abstrakcyjnej, w przeciwnym razie zostanie podany błąd kompilacji.
1- Twój interfejs Powinien być czysty, co oznacza, że interfejs funkcjonalny ma być implementowany przez klasy bezstanowe, na przykład czysty to
Comparator
interfejs, ponieważ nie zależy od stanu implementującego, w tym przypadku nie zostanie podany żaden błąd kompilacji, ale w wielu przypadkach nie będzie w stanie używać lambdy z tego rodzaju interfejsamijava.util.function
Pakiet zawiera różne funkcjonalne interfejsy ogólnego zastosowania, takie jakPredicate
,Consumer
,Function
, iSupplier
.Pamiętaj również, że możesz używać lambd bez tej adnotacji.
źródło
Oprócz innych odpowiedzi, myślę, że głównym powodem, dla którego „dlaczego używanie interfejsu funkcjonalnego innego niż bezpośrednio z wyrażeniami lambda” może być związane z naturą języka Java, który jest zorientowany obiektowo.
Główne atrybuty wyrażeń Lambda to: 1. Można je przekazywać 2. i wykonywać w przyszłości w określonym czasie (kilka razy). Aby obsługiwać tę funkcję w językach, niektóre inne języki po prostu zajmują się tą sprawą.
Na przykład w Java Script funkcja (funkcja anonimowa lub literały funkcyjne) może być adresowana jako obiekt. Możesz więc je łatwo utworzyć, a także przypisać je do zmiennej i tak dalej. Na przykład:
lub przez ES6, możesz użyć funkcji strzałki.
Do tej pory projektanci języka Java nie akceptowali obsługi wspomnianych funkcji w ten sposób (techniki programowania funkcjonalnego). Uważają, że język Java jest zorientowany obiektowo i dlatego powinni rozwiązać ten problem za pomocą technik zorientowanych obiektowo. Nie chcą przegapić prostoty i spójności języka Java.
Dlatego używają interfejsów, ponieważ gdy obiekt interfejsu z tylko jedną metodą (mam na myśli interfejs funkcjonalny) jest potrzebny, można go zastąpić wyrażeniem lambda. Jak na przykład:
źródło