Wyrażenie lambda a odniesienie do metody [zamknięte]

114

IntelliJ ciągle proponuje mi zastąpienie wyrażeń lambda odwołaniami do metod.

Czy jest między nimi jakaś obiektywna różnica?

Gerard
źródło
4
Niezupełnie, nie widzę żadnego obiektu! To wygląda na statyczne wezwanie do mnie
Gerard
9
Oczywiście! Ale „nie znajdziesz” też… To kwestia gustu, bardziej martwiłem się o aspekty techniczne. W rzeczywistości, jak już powiedziałeś, że są takie same, jest to dla mnie dobra odpowiedź. W każdym razie, zgodnie z propozycją IntelliJ, myślę, że generalnie bardziej cenione jest zobaczenie odniesienia do metody niż lambda (chociaż nie dla mnie).
Gerard
15
Kod wyrażenia lambda jest kompilowany do metody syntetycznej, podczas gdy odwołania do metod działają bez (wyjątek: specjalne konstrukcje, takie jak Type[]::new). Klasa anonimowa wygenerowana w czasie wykonywania będzie taka sama. Środowisko JRE nie robi między nimi żadnej różnicy. Zatem użycie odwołania do metody pozwoli Ci zaoszczędzić jedną metodę w skompilowanym kodzie, z drugiej strony nie możesz się na nich zatrzymać podczas debugowania krok po kroku…
Holger
6
Teraz pytanie zostanie zamknięte ... Szkoda dla wszystkich użytkowników takich jak ja, którzy nie znają różnicy między lambdami a referencjami, nawet jeśli nie ma żadnej decydującej. Zastanawiam się też, dlaczego nikt nie odważył się na to odpowiedzieć? To jest dla mnie właściwa odpowiedź.
Gerard
3
Udzielenie odpowiedzi na zamknięte pytanie sprzed dwóch lat jest prawdopodobnie złym pomysłem, ale dla tych, którzy NAPRAWDĘ CZYTALI to pytanie, oto co mówi samouczek Oracle ( docs.oracle.com/javase/tutorial/java/javaOO/ ... ): Odniesienia do metod ... kompaktowe, łatwe do odczytania wyrażenia lambda dla metod, które mają już nazwę.
jutro

Odpowiedzi:

187

Pozwólcie, że przedstawię pewne spojrzenie na to, dlaczego dodaliśmy tę funkcję do języka, skoro wyraźnie nie było to konieczne (wszystkie referencje metod można wyrazić jako lambdy).

Zauważ, że nie ma dobrej odpowiedzi . Każdy, kto mówi „zawsze używaj ref metody zamiast lambda” lub „zawsze używaj lambda zamiast odniesienia do metody” powinien zostać zignorowany.

To pytanie jest bardzo podobne w duchu do „kiedy powinienem używać nazwanej klasy, a kiedy anonimowej”? Odpowiedź jest taka sama: kiedy uznasz, że jest bardziej czytelny . Z pewnością są przypadki, które są zdecydowanie jednym lub zdecydowanie drugim, ale w środku jest mnóstwo szarości i należy zastosować ocenę.

Teoria stojąca za referencjami metod jest prosta: nazwy mają znaczenie . Jeśli metoda ma nazwę, to odwoływanie się do niej po nazwie, a nie za pomocą imperatywnego zbioru kodu, który ostatecznie po prostu obraca się i wywołuje ją, jest często (ale nie zawsze!) Bardziej przejrzyste i czytelne.

Spory o wydajność lub liczenie postaci to głównie czerwone śledzie i należy je zignorować. Celem jest napisanie kodu, który będzie krystalicznie jasny, co robi. Bardzo często (ale nie zawsze!) Referencje metod wygrywają w tym wskaźniku, więc włączyliśmy je jako opcję do wykorzystania w takich przypadkach.

Kluczową kwestią dotyczącą tego, czy odwołania do metod wyjaśniają, czy zaciemniają intencję, jest to, czy z kontekstu jasno wynika, jaki jest kształt reprezentowanej funkcji. W niektórych przypadkach (np. map(Person::getLastName)Z kontekstu jasno wynika, że ​​wymagana jest funkcja, która odwzorowuje jedną rzecz na drugą, aw takich przypadkach lśnią odniesienia do metod. W innych użycie ref do metody wymaga od czytelnika zastanowienia się, jakiego rodzaju funkcji; jest to znak ostrzegawczy, że lambda może być bardziej czytelna, nawet jeśli jest dłuższa.

Wreszcie, odkryliśmy, że większość ludzi na początku unika odwołań do metod, ponieważ czują się jeszcze nowsze i dziwniejsze niż lambdy, więc początkowo uważają je za „mniej czytelne”, ale z czasem, gdy przyzwyczają się do składni, ogólnie zmieniają swoje zachowanie i skłaniają się ku odniesieniom do metod, kiedy tylko mogą. Bądź więc świadomy, że Twoja subiektywna, początkowa, „mniej czytelna” reakcja prawie na pewno pociąga za sobą jakiś aspekt stronniczości rodzinnej i powinieneś dać sobie szansę oswoić się z oboma przed wyrażeniem opinii stylistycznej.

Brian Goetz
źródło
25
@Gerard Dziękuję, byłaby lepsza odpowiedź.
Yassin Hajaj
3
@Gerard Wygląda na to, że Brian mówi „Nie, nie ma”
dj18
Brian, otrzymuję różne wyniki, używając odwołania do metody i lambda dla tej samej metody. Czy nie powinny być wymienne?
Michel Feinstein
@mFeinstein Dla każdej referencji metody istnieje równoważna lambda (której możesz użyć lub nie). Opublikuj kod jako pytanie?
Brian Goetz
Chcę, ale obawiam się, że kod może być zbyt duży, ponieważ jest to Android LiveDatawewnątrz a Fragment, który przekonwertowałem na program Eventuruchamiany przez a ViewModel... i inne zachowanie ma miejsce, gdy Android wraca do tego samego Fragment... . więc trudno mi to uprościć do pytania
Michel Feinstein
10

Długie wyrażenia lambda składające się z kilku instrukcji mogą zmniejszyć czytelność kodu. W takim przypadku wyodrębnienie tych instrukcji w metodzie i odwołanie się do niej może być lepszym wyborem.

Innym powodem może być możliwość ponownego użycia . Zamiast kopiować i wklejać wyrażenie lambda składające się z kilku instrukcji, możesz skonstruować metodę i wywołać ją z różnych miejsc kodu.

ovunccetin
źródło
3
Porównaj: houses.map(House::getName)i houses.map(h -> h.getName()). Lambda zajmuje dwa mniej znaków. Prawdą jest, że typ nie jest jawny, ale każde IDE powiedziałoby ci, a poza tym lambdy powinny być używane, gdy typ jest oczywisty. Mogę się z tobą zgodzić co do możliwości ponownego użycia, ale lambdy są dokładnie małe, więc można je łączyć, zamiast tworzyć duże, specyficzne metody. W tym sensie małe metody są bardziej wielokrotnego użytku niż niektóre duże i złożone metody, a ze względu na przejrzystość lambd (i do pewnego stopnia szczegółowość) są nadal łatwe do odczytania.
Gerard
11
Jestem z Geraldem. Czytelność faktycznie cierpi, kiedy przenosisz kod, więc musisz przeskoczyć do niego, aby kontynuować czytanie, a następnie skoczyć z powrotem. Ty chcesz mieć wszystkie istotne kod w tym samym miejscu. Ponadto, Housejest to bardzo łagodny przykład; co z ThreeStoryRedBrickHouseWithBlueDoors. Preferuję odwołania do metod dla wyrażeń lambda z wieloma argumentami, a czasem podkreślam, że lambda dotyczy tylko jednego wywołania metody. Jest mniej błędów w odwołaniu do metody: możesz źle napisać argument w miejscu użycia, przypadkowo odwołać się do zmiennej z zakresu zewnętrznego itp.
Marko Topolnik
@Gerard Nie zgadzam się z twoim pierwszym stwierdzeniem. Jeśli używasz dobrze opisujących nazw metod i wyodrębniasz duże stosy kodu, ruchomy kod poprawia czytelność. Jeśli używasz zaciemniających nazw metod, zgadzam się z tobą.
Torsten