Gdy iteruję kolekcję przy użyciu nowego cukru syntaktycznego Java 8, takiego jak
myStream.forEach(item -> {
// do something useful
});
Czy nie jest to równoważne z fragmentem „starej składni” poniżej?
myStream.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
// do something useful
}
});
Czy to oznacza, że Consumer
za każdym razem, gdy iteruję kolekcję, tworzony jest nowy anonimowy obiekt? Ile miejsca to zajmuje? Jakie ma to wpływ na wydajność? Czy to oznacza, że powinienem raczej używać starego stylu dla pętli podczas iteracji w dużych wielopoziomowych strukturach danych?
Odpowiedzi:
Jest równoważny, ale nie identyczny. Mówiąc prosto, jeśli wyrażenie lambda nie przechwytuje wartości, będzie to singleton, który jest ponownie wykorzystywany przy każdym wywołaniu.
Zachowanie nie jest dokładnie określone. JVM ma dużą swobodę w implementacji. Obecnie JVM Oracle tworzy (przynajmniej) jedną instancję na wyrażenie lambda (tzn. Nie dzieli instancji między różnymi identycznymi wyrażeniami), ale tworzy singletony dla wszystkich wyrażeń, które nie przechwytują wartości.
Możesz przeczytać tę odpowiedź, aby uzyskać więcej informacji. Tam podałem nie tylko bardziej szczegółowy opis, ale także przetestowałem kod, aby zaobserwować obecne zachowanie.
Jest to objęte specyfikacją języka Java®, rozdział „ 15.27.4. Ocena wyrażeń lambda w czasie wykonywania ”
Streszczony:
źródło
Kiedy instancja reprezentująca lambda jest tworzona z wyczuciem, zależy od dokładnej zawartości twojego ciała lambda. Mianowicie, kluczowym czynnikiem jest to, co lambda wychwytuje ze środowiska leksykalnego. Jeśli nie przechwytuje żadnego stanu, który jest zmienny od stworzenia do stworzenia, instancja nie zostanie utworzona za każdym razem, gdy zostanie wprowadzona pętla dla każdego z nich. Zamiast tego w czasie kompilacji zostanie wygenerowana metoda syntetyczna, a witryna użytkowania lambda otrzyma po prostu obiekt singletonu, który deleguje tę metodę.
Ponadto należy pamiętać, że ten aspekt jest zależny od implementacji i można oczekiwać przyszłych udoskonaleń i ulepszeń HotSpot w kierunku większej wydajności. Istnieją ogólne plany np. Stworzenia lekkiego obiektu bez pełnej odpowiedniej klasy, która ma wystarczającą ilość informacji do przekazania do jednej metody.
Oto dobry, dostępny dogłębny artykuł na ten temat:
http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
źródło
Przekazujesz nową instancję do
forEach
metody. Za każdym razem, gdy to robisz, tworzysz nowy obiekt, ale nie jeden dla każdej iteracji pętli. Iteracja odbywa się wforEach
metodzie przy użyciu tej samej instancji obiektu „callback”, dopóki nie zostanie wykonana w pętli.Tak więc pamięć używana przez pętlę nie zależy od wielkości kolekcji.
Tak. Ma niewielkie różnice na bardzo niskim poziomie, ale nie sądzę, żebyś się nimi przejmował. Wyrażenia Lamba używają funkcji invokedynamic zamiast klas anonimowych.
źródło