Referencje do metod

W ostatnim wpisie opisałem wam sytuację w której mój IDE podpowiedział mi o możliwości wymiany argumentu, którym była klasa anonimowa na wyrażenie typu lambda. W pewnym momencie jednak zauważyłem, że w niektórych przypadkach narzędzie to ciągle daje mi do zrozumienia, że coś tutaj mogłoby zostać uproszczone. Dowiedziałem się wtedy, że niektóre z tych wyrażeń mogę jeszcze bardziej skrócić zastępując je referencjami do metod. Zapraszam do lektury.

Czym są referencje do metod?

Referencja do metod (z ang. method reference) jest funkcjonalnością powiązaną z wyrażeniami lambda. Są to odwołania do istniejących już metod.

Jeszcze raz, dokładniej. W przypadku użycia wyrażeń typu lambda mamy dwie możliwości. Albo tworzymy anonimowe metody, albo wykorzystujemy już istniejące. W przypadku tych drugich możemy zastąpić je referencjami do metod. Zaraz pokażę w jaki sposób.

Budowa referencji do metod

Klasa::metoda

Na przykład wyrażenie typu lambda zapisane w taki sposób:

możemy zastąpić takim zapisem:

Kiedy tworzymy a kiedy wykorzystujemy?

Odpowiadając na to pytanie tak naprawdę odpowiemy sobie kiedy możemy wykorzystać referencje do metod. Wyobraźmy sobie, że chcemy posortować listę studentów ze względu na osiągniętą przez nich średnią ocen. Mamy dwie możliwości.

Pierwsza jest taka, że nasza klasa Student zawiera w sobie jedynie imię, nazwisko oraz średnią ocen. W takim przypadku, gdy chcemy porównać dwóch uczestników wykorzystujemy wyrażenie typu lambda, które jest znacznie krótsze od zwyczajnej klasy anonimowej. Pomimo, że linijka sama w sobie jest długa, jest ona czytelna i każdy kto programuje od jakiegoś czasu nie będzie miał z nią problemu.

Okazuje się jednak, że w przypadku gdy nasza klasa Student posiadałaby statyczną metodę która przyjmuje dwóch studentów jako parametry i jako wynik zwracała wartość int zależną od wyniku porównania, możemy zastąpić to referencją do tej właśnie metody. Uproszczając tym samym uproszczone już wyrażenie lambda.

Poniżej przykładowy kod z zastosowaniem powyższego przykładu.

Rodzaje referencji do metod

Okazuje się jednak, że to nie koniec naszych zmagań. Referencje do metod dzielimy na cztery typy:

Referencje do metody statycznej

KlasaZawierająca::metodaStatyczna
Przykład którym posłużyłem się wcześniej był właśnie taką referencją.

Referencja do metody należącej do konkretnej instancji

obiektZawierający::nazwaMetody
Jest to przypadek bardzo podobny do poprzedniego. Gdy jednak metoda której potrzebujemy nie jest statyczna, aby się do niej odwołać musimy najpierw utworzyć instancję danego obiektu.

Możemy oczywiście także skorzystać z metody jednego z obiektów które porównujemy, aby uniknąć sytuacji która wystąpiła w powyższym przykładzie – tworzenia obiektu, który nic dla nas nie znaczy. Zachęcam też do próby edycji kodu z przykładu pierwszego, tak aby posortował nasz ciąg przy pomocy referencji do metody instancji.

Referencja do metody konkretnego typu, bez precyzowania instancji

Typ::nazwaMetody
Tutaj z pewnością najciekawszy przypadek.

Dodajmy do naszej klasy Student dodatkową metodę porównującą.

Jak wiemy, interfejs funkcyjny, który staramy się uzupełnić wymaga od nas podania dwóch argumentów, które zostaną ze sobą porównane. Możemy to jednak obejść. W przypadku tej referencji nasza metoda zostaje wywołana na pierwszym obiekcie wstawiając pozostałe jako parametry. Dlatego wymagany przez nas dwa parametry tak naprawdę zastępujemy jednym. Do naszego interfejsu Comparatora zamiast wstawić metoda(TypA a, TypB b), wstawiamy a.metoda(b). Dzięki temu możemy zastosować taki zapis.

Jest to także najtrudniejszy i najmniej oczywisty przypadek, dlatego szczególnie zachęcam do próby napisania własnego, niekoniecznie długiego kodu. Do tego oczywiście przykład. Dodałem w nim System.out.println w metodzie comp, żebyście mogli sami sprawdzić w jaki dokładnie sposób zostają one wywoływane (właściwie na których obiektach).

Referencja do konstruktora

NazwaKlasy::new
Jest to już ostatni przypadek. Pozwala on nam przypisanie referencji konstruktora do zmiennej. Po odwołaniu się do niego poprzez wcześniej zadeklarowaną zmienną, otrzymamy obiekt typu klasy, z której pochodzi dany konstruktor.

Po przypisaniu zmiennej mamy możliwość tworzenia obiektów przy pomocy metody którą zadeklarowaliśmy wcześniej w naszym interfejsie funkcyjnym.

Interfejs:

Odwołanie do konstruktora, który zwraca nam obiekty swojego typu.

W tym przypadku oczywiście także polecam zajrzeć do przykładowego kodu.

Przykład zastosowania

Na sam koniec przygotowałem jeszcze jeden przykład zastosowania referencji do metod. Jeżeli dotarłeś do tego miejsca oznacza to, że temat Cię zainteresował. Dobrze. W tym przykładzie wyświetlimy tylko tych studentów z listy, którzy mają średnią wyższą niż tą przez nas zdefiniowaną. Wykorzystałem tutaj referencję do instancji System.out oraz interfejsy funkcyjne Predicate oraz Consumer.

Takim oto sposobem dotarliśmy do samego końca. Gratuluję wytrwałości i zachęcam do przećwiczenia kodu. Z własnego doświadczenia wiem, że sama teoria nie wystarcza aby poprawnie oraz wystarczająco szybko stosować wszystkie zagadnienia, których się nauczyliśmy. Następny wpis w przyszłą niedzielę! Miłego wieczoru.

Your email address will not be published. Required fields are marked *

*