Czy wprowadzenie nowej notacji lambda (patrz np. Ten artykuł ) w Javie 8 będzie wymagało pewnego rodzaju wnioskowania typu?
Jeśli tak, to w jaki sposób nowy system typów wpłynie na język Java jako całość?
Czy wprowadzenie nowej notacji lambda (patrz np. Ten artykuł ) w Javie 8 będzie wymagało pewnego rodzaju wnioskowania typu?
Jeśli tak, to w jaki sposób nowy system typów wpłynie na język Java jako całość?
Odpowiedzi:
Jest sporo niepoprawnych informacji w odpowiedzi maniaka grzechotki i w wątku komentarza. Odpowiem tutaj, ponieważ komentarz jest za mały. Ponadto, skoro to odpowiedź, w końcu spróbuję odpowiedzieć na pierwotne pytanie. (Zauważ jednak, że nie jestem ekspertem od systemów typu).
Po pierwsze, krótkie odpowiedzi na pierwotne pytanie brzmią: tak i nie. Tak, Java 8 będzie miała znacznie więcej wnioskowania o typie niż Java 7, i nie, nie ma „nowego” systemu typów w Javie 8, chociaż są pewne drobne zmiany .
Java 8 nadal będzie typowana statycznie i nadal będzie miała dychotomię między klasami i interfejsami. Nie ma żadnych nowych typów, takich jak typy funkcji. Typ lambda jest zasadniczo „interfejsem funkcjonalnym”, który jest zwykłym interfejsem z pojedynczą metodą abstrakcyjną.
Interfejsy mogą teraz mieć kod w postaci metod domyślnych, ale model pojedynczego dziedziczenia klas i wielokrotnego dziedziczenia interfejsów pozostaje taki sam. Oczywiście są pewne korekty, takie jak reguły rozwiązywania metod w obecności metod domyślnych, ale podstawy pozostają niezmienione.
Każdy typ, który można wywnioskować na podstawie wnioskowania o typie, może zostać zapisany jawnie. Aby użyć przykładu maniaka ratchet ,
Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });
jest w zasadzie cukrem dla
Collections.<MyClass>sort(list,
(Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));
Zatem stwierdzenie sparkleshy „wnioskowanie typu nie wymaga żadnego rozszerzenia systemu typów” jest w zasadzie poprawne.
Ale wracając do cukru syntaktycznego, powtórzę moje stwierdzenie, że wyrażenie lambda nie jest cukrem syntaktycznym dla anonimowej klasy wewnętrznej. Dziwak Ratchet stwierdził, że wyrażenie lambda jest tłumaczone na anonimową instancję klasy wewnętrznej, a Sparkleshy po prostu potwierdził, że lambda jest cukrem syntaktycznym dla anonimowej klasy wewnętrznej, ale te stwierdzenia są niepoprawne. Prawdopodobnie są oparte na nieaktualnych informacjach. Wczesne implementacje lambda wprowadzały lambdy w ten sposób, ale wszystko się zmieniło.
Wyrażenia lambda różnią się semantycznie od klas wewnętrznych i są implementowane inaczej niż klasy wewnętrzne.
Wyrażenia lambda różnią się semantycznie od klas wewnętrznych na kilka sposobów. Ocena wyrażenia lambda nie musi za każdym razem tworzyć nowej instancji. Mają także inną semantykę przechwytywania, na przykład przechwytują to inaczej. W wewnętrznej klasy, to jest wewnętrzną przykład klasy, natomiast w lambda, to jest to przypadek obejmujących. Rozważ następujące:
public class CaptureThis {
void a(Runnable r) { r.run(); }
void b() {
a(new Runnable() { public void run() { System.out.println(this); }});
a(() -> System.out.println(this));
}
public String toString() { return "outer"; }
public static void main(String[] args) { new CaptureThis().b(); }
}
W najnowszej wersji JDK 8 lambda (użyłem b69 ), wynik będzie podobny do następującego:
CaptureThis$1@113de03
outer
Ponadto wyrażenia lambda są implementowane zupełnie inaczej niż klasy wewnętrzne. Jeśli porównasz zdemontowane dane wyjściowe, zobaczysz, że kod klasy wewnętrznej bezpośrednio kompiluje się do stworzenia i wywołuje konstruktor CaptureThis 1 USD, podczas gdy wyrażenie lambda kompiluje się do wywołanej instrukcji dynamicznej, która wywołuje Runnable w sposób nieokreślony. Pełne wyjaśnienie tego, jak to działa i dlaczego, znajduje się w wykładzie JavaOne 2012 Briana Goetza Lambda: A Peek Under The Hood .
this
przezMyClass.this