Pojawił się nowy szum z długo oczekiwanymi wyrażeniami lambda w Javie 8; co 3 dni pojawia się z nimi kolejny artykuł o tym, jak fajni są.
O ile rozumiem wyrażenie lambda jest niczym więcej niż anonimową klasą wewnętrzną z jedną metodą (przynajmniej na poziomie kodu bajtowego). Poza tym ma jeszcze jedną fajną funkcję wnioskowania o typie, ale uważam, że równoważność tego można uzyskać na pewnym poziomie za pomocą generycznych (oczywiście nie w tak zgrabny sposób, jak w przypadku wyrażeń lambda).
Wiedząc o tym, czy wyrażenia lambda przyniosą coś więcej niż tylko słodzenie syntaktyczne w Javie? Czy mogę tworzyć mocniejsze i bardziej elastyczne klasy lub inne konstrukcje obiektowe z wyrażeniami lambda, których nie można zbudować przy użyciu bieżących funkcji językowych?
źródło
this
naOuterClass.this
jest częścią procesu odsławiania wyrażeń lambda na anonimową klasę.Odpowiedzi:
tl; dr: chociaż jest to głównie cukier składniowy, ta ładniejsza składnia czyni wiele rzeczy praktycznymi, które kończyły się nieskończonymi, nieczytelnymi liniami nawiasów klamrowych i nawiasów.
Cóż, w rzeczywistości jest odwrotnie, ponieważ lambdas są znacznie starsze niż Java. Anonimowe klasy wewnętrzne za pomocą jednej metody są (były) najbliższą Javą dostępną dla lambdas. To przybliżenie, które było „wystarczająco dobre” przez jakiś czas, ale ma bardzo nieprzyjemną składnię.
Na powierzchni lambda Java 8 wydają się być niewiele więcej niż cukrem syntaktycznym, ale kiedy spojrzysz pod powierzchnię, zobaczysz mnóstwo interesujących abstrakcji. Na przykład specyfikacja JVM traktuje lambda zupełnie inaczej niż obiekt „prawdziwy” i chociaż można obsługiwać je tak, jakby były obiektami, JVM nie musi ich implementować.
Ale chociaż cała ta sztuczka techniczna jest interesująca i istotna (ponieważ umożliwia przyszłe optymalizacje w JVM!), Prawdziwą korzyścią jest „tylko” składniowa część cukrowa.
Co jest łatwiejsze do odczytania:
lub:
lub (używając uchwytu metody zamiast lambda):
Fakt, że w końcu możesz wyrazić w zwięzły sposób, który wcześniej byłby 5 liniami kodu (z których 3 są całkowicie nudne), wprowadza prawdziwą zmianę tego, co jest praktyczne (ale nie to, co jest możliwe, przyznane).
źródło
List
może pomieścić dowolny obiekt,List<String>
może „tylko” przechowywać ciągi znaków. Generics dodał ograniczenie (i opcję sformalizowania ograniczeń!), A nie dodatek mocy. Prawie wszystko od czasu Java 1.1 jest cukrem syntaktycznym. I to niekoniecznie zła rzecz.List<String>
jest tylkoList
rzutowaniem, abyString
dodać wokół niektórych zwracanych wartości. Niemniej jednak są one niezwykle przydatne i znacznie ułatwiają pisanie w języku. Podobnie jest w przypadku Lambdas.W przypadku Javy jest to lepszy sposób na stworzenie anonimowej klasy wewnętrznej. Wynika to z fundamentalnej decyzji w Javie, że każdy kawałek kodu bajtowego musi mieszkać w określonej klasie, której nie można zmienić po dziesięcioleciach kodu starszego typu.
Jednak nie o to tak naprawdę chodzi w wyrażeniach lambda. W formalizmach, w których są one rodzimymi pojęciami, a nie wyskokiem z wózka, lambdas są podstawowymi elementami składowymi; zarówno ich składnia, jak i stosunek ludzi do nich są bardzo różne. Przykład anonimowej funkcji rekurencyjnej utworzonej wyłącznie z lambd w Strukturze i interpretacji programów komputerowych może zmienić całą twoją koncepcję obliczeń. (Jestem jednak pewien, że ten sposób uczenia się programowania jest po prostu ezoteryczny, aby stać się historią sukcesu głównego nurtu.)
źródło
Tak, to tylko cukier syntaktyczny, w tym sensie, że gdziekolwiek napiszesz lambdę, możesz ponownie napisać to wyrażenie jako anonimowe wyrażenie klasy wewnętrznej za pomocą jednej metody, w której klasa implementuje interfejs funkcjonalny wywnioskowany z kontekstu lambda, i byłby dokładnie równoważny semantycznie. Możesz to zrobić, po prostu zastępując wyrażenie lambda anonimowym wyrażeniem klasy, bez zmiany jakiegokolwiek innego wyrażenia lub wiersza kodu.
źródło
this
trzeba będzie przekonwertować jąOuterClass.this
. Nie przeczy to temu, co powiedziałem - każde wyrażenie lambda można przekształcić w semantycznie równoważne anonimowe wyrażenie klasowe, nie zmieniając niczego poza tym wyrażeniem . Nie powiedziałem, że wnętrze się nie zmieni.this
w lambda jest częścią cukru syntaktycznego i nie ma różnicy w semantyce. I o różnicach w implementacji, implementacji! = Semantyka. O różnicach w tożsamości obiektu; tożsamość obiektu jest niezwykle styczna do funkcjonalności lambd; i tak nikt nie sprawdza tożsamości obiektów klas lambdas / anon, ponieważ nie jest to przydatne.Joachim Sauer wykonał już dobrą robotę, odpowiadając na twoje pytanie, ale wskazał tylko na coś, co uważam za ważne. Ponieważ Lambdas nie są klasami, nie są również kompilowane jako takie. Wszystkie anonimowe klasy wewnętrzne powodują utworzenie pliku .class, który z kolei musi zostać załadowany przez ClassLoader. Dlatego użycie Lambdas nie tylko sprawia, że kod jest piękniejszy, ale także zmniejsza rozmiar skompilowanego kodu, wielkość pamięci ClassLoadera i czas potrzebny na przesłanie bitów z dysku twardego.
źródło
Nie oni nie są.
Innym sposobem, by to ująć, jest to, że lambdas są zorientowanym na obiekt, ale zwięzłym, sposobem osiągnięcia tego samego, co klasa anonimowa lub, moim zdaniem, klasa wewnętrzna osiągnęłyby w sposób zorientowany obiektowo.
źródło