Zawsze zastanawiałem się, dlaczego Java nie korzysta z wnioskowania o typie, biorąc pod uwagę, że język jest tym, czym jest, a jego maszyna wirtualna jest bardzo dojrzała. Google's Go jest przykładem języka z doskonałym wnioskowaniem na temat tekstu i ogranicza liczbę operacji pisania. Czy jest jakiś szczególny powód, dla którego ta funkcja nie jest częścią Javy?
44
Odpowiedzi:
Technicznie rzecz biorąc, Java korzysta z wnioskowania typu podczas korzystania z generycznych. Za pomocą ogólnej metody, takiej jak
Kompilator przeanalizuje i zrozumie to podczas pisania
Ciąg znaków zostanie zwrócony dla pierwszego wywołania, a liczba całkowita dla drugiego wywołania na podstawie tego, co podano jako argument. W rezultacie otrzymasz odpowiednie sprawdzanie czasu kompilacji. Ponadto w Javie 7 można uzyskać dodatkowe wnioskowanie o typach podczas tworzenia instancji podobnych
Java jest na tyle uprzejma, aby wypełnić dla nas puste nawiasy kątowe. Dlaczego Java nie obsługuje wnioskowania o typach w ramach przypisywania zmiennych? W pewnym momencie istniało RFE do wnioskowania typu w deklaracjach zmiennych, ale zostało to zamknięte jako „Nie naprawi”, ponieważ
Współautor, który to zamknął, zauważył również, że jest to po prostu „nie-java-podobne”, z którym jestem jednym z nich się zgodzić. Szczegółowość Javy może być zarówno błogosławieństwem, jak i przekleństwem, ale sprawia, że język jest tym, czym jest.
Oczywiście ten konkretny RFE nie był końcem tej rozmowy. W Javie 7 ponownie rozważono tę funkcję , tworząc niektóre implementacje testowe, w tym jedną przez Jamesa Goslinga. Ponownie ta funkcja została ostatecznie zestrzelona.
Wraz z wydaniem Java 8 możemy teraz wnioskować o typie jako część lambd jako takich:
Kompilator Java może patrzeć sposobu
Collections#sort(List<T>, Comparator<? super T>)
i interfejsuComparator#compare(T o1, T o2)
i określenia,first
orazsecond
powinno byćString
w ten sposób pozwalając na programator zrezygnować konieczności przekształca typu w wyrażeniu lambda.źródło
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns
- tak, jeśli tak, toHashMap<String, Integer> map = foo.getMap()
zgadzam się - w C # zwykle nie używamvar
w takich przypadkach, nawet jeśli mógłbym. Ale ten argument nie trzyma wody, jeśli jestHashMap<String, Integer> map = new HashMap<String, Integer>()
. To prawdziwa redundancja i nie widzę żadnej korzyści z konieczności dwukrotnego wpisywania nazwy typu. A w jaki sposób skorzystałbym z kontroli krzyżowej kompilatora, nie rozumiem wcale.var
w Javie.Humans benefit from the redundancy
jest prawdziwą odpowiedzią na bieżące pytanie, ponieważ każde uzasadnienie, które przeczytałem, wydaje się nieuzasadnioną, bezzasadną i niedorzeczną wymówką od projektantów Java: zarówno C #, jak i C ++ mają tę funkcję, projektanci C # i C ++ są nie mniej kompetentni niż Java i wszyscy chętnie z niego korzystają. Co powoduje, że programiści Java różnią się od programistów C # lub C ++? Właśnie dlatego zgadzam się z @KonradMorawski: „Oto, jak tu się wszystko robi” ponownie wydaje się być prawdziwym powodem tego za kulisami.Po pierwsze, wnioskowanie typu nie ma nic wspólnego z dojrzałością środowiska uruchomieniowego, niezależnie od tego, czy jest to 30-letni procesor, czy maszyna wirtualna, która jest tak nowa, że bity są nadal błyszczące. chodzi o kompilator.
To powiedziawszy, jest dozwolone w przypadku rodzajów ogólnych, a powodem, dla którego nie jest dozwolone w przypadku typów innych niż ogólne, wydaje się być filozofia - nic nie stoi na przeszkodzie, aby projektanci go dodali.
Aktualizacja: wygląda na to, że Java 10 ją obsługuje —- http://openjdk.java.net/jeps/286
źródło
O ile wiem, kiedy Java była projektowana na początku lat dziewięćdziesiątych, wnioskowanie o typach nie było tak popularne wśród języków głównego nurtu (ale było to już bardzo dobrze znane pojęcie, np. W ML). Mogę sobie wyobrazić, że wnioskowanie typu prawdopodobnie nie było obsługiwane, ponieważ Java była skierowana do programistów pochodzących z C ++, Pascal lub innych języków głównego nurtu, które jej nie miały (zasada najmniejszego zaskoczenia).
Ponadto jedną z zasad projektowania Java jest pisanie rzeczy w sposób jawny, aby upewnić się, że programista i kompilator rozumieją kod w taki sam sposób: powielanie informacji zmniejsza ryzyko błędów. Oczywiście może być kwestią gustu, czy wpisanie kilku dodatkowych znaków jest warte dodatkowego bezpieczeństwa, jakie zapewnia, ale taka była filozofia projektowania zastosowana w Javie: pisz wyraźnie.
Nie wiem, czy Java będzie w przyszłości rozpoznawać typy, ale IMO byłoby wielką rewolucją dla tego języka (jak wspomniał Glenn Nelson, został opisany jako „nie-java-podobny”), a następnie można rozważyć odrzucenie nazwij Java na rzecz nowej nazwy.
Jeśli chcesz używać języka JVM z wnioskowaniem typu, możesz użyć Scali.
źródło
Mogę wymyślić kilka możliwych przyczyn. Jednym z nich jest to, że wyraźne pisanie jest samo-dokumentowaniem. Java ogólnie sprawia, że jest to priorytet nad zwięzłością. Innym powodem mogą być przypadki, gdy typ jest nieco niejednoznaczny. Na przykład, gdy typ lub dowolny podtyp może spełniać procedurę. Powiedzmy, że chcesz użyć Listy, ale ktoś przychodzi i używa metody wyłącznie dla ArrayList. JIT wnioskuje o ArrayList i kontynuuje działanie, nawet jeśli potrzebujesz błędu kompilacji.
źródło
Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error
- Nie rozumiem tego trochę. Wnioskowanie typu odbywa się w momencie inicjowania zmiennej, a nie wywoływania w niej metody. Czy mógłbyś pokazać przykład, co miałeś na myśli?Jest to sprzeczne z dobrze ugruntowanym zaleceniem, aby deklarować zmienne przy użyciu najbardziej ogólnego interfejsu, który będzie pasował do twoich potrzeb, i inicjować je za pomocą odpowiedniej klasy implementacyjnej, jak w
Efektywnie,
jest niczym innym jak cukrem syntaktycznym
Jeśli chcesz, twoje IDE może wygenerować je z
new ArrayList<String>()
wyrażenia za pomocą „jednego kliknięcia” (refaktoryzuj / stwórz zmienną lokalną), ale pamiętaj, że jest to sprzeczne z zaleceniem „użyj interfejsów”.źródło