Ponieważ Java8 została niedawno wydana, a jej zupełnie nowe wyrażenia lambda wyglądają na naprawdę fajne, zastanawiałem się, czy oznacza to upadek klas Anonymous, do których byliśmy tak przyzwyczajeni.
Zbadałem trochę na ten temat i znalazłem kilka fajnych przykładów tego, jak wyrażenia lambda będą systematycznie zastępować te klasy, takie jak metoda sortowania Collection, która służyła do uzyskania anonimowej instancji komparatora w celu wykonania sortowania:
Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.firstName.compareTo(p2.firstName);
}
});
Teraz można to zrobić za pomocą Lambdas:
Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));
I wygląda zaskakująco zwięźle. Więc moje pytanie brzmi: czy jest jakiś powód, aby nadal używać tych klas w Javie8 zamiast Lambdas?
EDYTOWAĆ
To samo pytanie, ale w przeciwnym kierunku, jakie są korzyści z używania Lambd zamiast klas anonimowych, skoro Lambdas można używać tylko z interfejsami jednej metody, czy ta nowa funkcja jest tylko skrótem używanym tylko w kilku przypadkach, czy jest naprawdę przydatna?
źródło
Comparator.comparing(Person::getFirstName)
jeśligetFirstName()
byłaby to metoda zwracającafirstName
.Odpowiedzi:
Anonimowej klasy wewnętrznej (AIC) można użyć do utworzenia podklasy klasy abstrakcyjnej lub klasy konkretnej. AIC może również zapewnić konkretną implementację interfejsu, w tym dodanie stanu (pól). Do instancji AIC można odwoływać się przy użyciu
this
jej treści metod, więc można na niej wywoływać dalsze metody, zmieniać jej stan w czasie itd. Żadne z nich nie mają zastosowania do lambd.Domyślam się, że większość zastosowań AIC polegała na zapewnieniu bezstanowych implementacji pojedynczych funkcji i dlatego można je zastąpić wyrażeniami lambda, ale są inne zastosowania AIC, dla których nie można używać lambd. AIC są tutaj.
AKTUALIZACJA
Inną różnicą między AIC a wyrażeniami lambda jest to, że AIC wprowadzają nowy zakres. Oznacza to, że nazwy są rozpoznawane z nadklas i interfejsów AIC i mogą przesłonić nazwy występujące w środowisku obejmującym leksyk. W przypadku lambd wszystkie nazwy są rozwiązywane leksykalnie.
źródło
A$1.class
ale Lambda nie. Czy mogę dodać to w Difference?LambdaClass$$Lambda$1/1078694789
. Jednak ta klasa jest generowana w locie przez metafabrykę lambda, a nie przezjavac
, więc nie ma odpowiedniego.class
pliku. Jest to jednak problem związany z wdrażaniem.Lambdy, choć świetna funkcja, będą działać tylko z typami SAM. Oznacza to, że interfejsy mają tylko jedną abstrakcyjną metodę. To się nie powiedzie, jeśli twój interfejs będzie zawierał więcej niż jedną metodę abstrakcyjną. Tutaj przydadzą się klasy anonimowe.
Więc nie, nie możemy po prostu ignorować anonimowych klas. I po prostu FYI, twoja
sort()
metoda może być bardziej uproszczona, pomijając deklarację typu dlap1
ip2
:Możesz również użyć tutaj odwołania do metody. Albo dodasz
compareByFirstName()
metodę wPerson
klasie i użyjesz:lub dodaj getter for
firstName
, pobierz bezpośrednio metodęComparator
fromComparator.comparing()
:źródło
new @MyTypeAnnotation SomeInterface(){};
. Nie jest to możliwe w przypadku wyrażeń lambda. Aby uzyskać szczegółowe informacje, zobacz moje pytanie tutaj: Dodawanie adnotacji do funkcjonalnego interfejsu wyrażenia Lambda .Wydajność lambda z klasami Anonymous
Po uruchomieniu aplikacji każdy plik klasy musi zostać załadowany i zweryfikowany.
Klasy anonimowe są przetwarzane przez kompilator jako nowy podtyp dla danej klasy lub interfejsu, więc dla każdej z nich zostanie wygenerowany nowy plik klasy.
Lambdy są inne przy generowaniu kodu bajtowego, są bardziej wydajne, używają dynamicznych instrukcji, które są dostarczane z JDK7.
W przypadku Lambdas ta instrukcja służy do opóźnienia tłumaczenia wyrażenia lambda w kodzie bajtowym do czasu wykonania. (instrukcja zostanie wywołana tylko po raz pierwszy)
W rezultacie wyrażenie lambda stanie się metodą statyczną (utworzoną w czasie wykonywania). (Istnieje niewielka różnica w przypadku stanów statycznych i przypadków stanowych, są one rozwiązywane za pomocą wygenerowanych argumentów metody)
źródło
invokedynamic
które jest generalnie wolniejsze niżinvokespecial
używane do tworzenia nowych instancji klas anonimowych. Tak więc w tym sensie lambdy są również wolniejsze (jednak JVM może optymalizowaćinvokedynamic
wywołania przez większość czasu).invokedynamic
z tym generowanie klas ad-hoc przebiega błyskawicznie w porównaniu do skompilowanych klas anonimowych.Istnieją następujące różnice:
1) Składnia
Wyrażenia lambda wyglądają zgrabnie w porównaniu z Anonimową Klasą Wewnętrzną (AIC)
2) Zakres
Anonimowa klasa wewnętrzna jest klasą, co oznacza, że ma zakres dla zmiennej zdefiniowanej wewnątrz klasy wewnętrznej.
Natomiast wyrażenie lambda nie jest własnym zakresem, ale jest częścią otaczającego zakresu.
Podobna reguła ma zastosowanie do super i tego słowa kluczowego podczas używania anonimowej klasy wewnętrznej i wyrażenia lambda. W przypadku anonimowej klasy wewnętrznej to słowo kluczowe odnosi się do zakresu lokalnego, a słowo kluczowe super odnosi się do superklasy anonimowej klasy. Podczas gdy w przypadku wyrażenia lambda to słowo kluczowe odnosi się do obiektu typu otaczającego, a super będzie odnosić się do superklasy otaczającej klasy.
3) Wydajność
W czasie wykonywania anonimowe klasy wewnętrzne wymagają ładowania klasy, alokacji pamięci oraz inicjalizacji obiektu i wywołania metody niestatycznej, podczas gdy wyrażenie lambda jest czystą czynnością czasu kompilacji i nie powoduje dodatkowych kosztów w czasie wykonywania. Zatem wydajność wyrażenia lambda jest lepsza w porównaniu z anonimowymi klasami wewnętrznymi. **
** Zdaję sobie sprawę, że ten punkt nie jest do końca prawdziwy. Szczegółowe informacje można znaleźć w poniższym pytaniu. Lambda vs anonimowa wydajność klasy wewnętrznej: zmniejszenie obciążenia ClassLoader?
źródło
Lambdy w Javie 8 zostały wprowadzone do programowania funkcjonalnego. Gdzie można uniknąć kodu standardowego. Natknąłem się na ten interesujący artykuł na temat lambda.
http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html
Zaleca się używanie funkcji lambda dla prostych logik. Jeśli implementacja złożonej logiki przy użyciu lambd będzie narzutem w debugowaniu kodu w przypadku problemu.
źródło
Klasy anonimowe istnieją na stałe, ponieważ lambda jest dobra dla funkcji z pojedynczymi metodami abstrakcyjnymi, ale we wszystkich innych przypadkach anonimowe klasy wewnętrzne są twoim wybawcą.
źródło
invoke dynamic
, lambda nie są konwertowane z powrotem na klasy anonimowe w czasie kompilacji (Java nie musi przechodzić przez tworzenie obiektów, tylko dbać o podpis metody, może powiązać się z metodą bez tworzenia obiektuźródło