JDK 7: Diamentowy operator

Project Coin zawiera liczne „drobne ulepszenia językowe” jako podzbiór nowych funkcji JDK 7. Niedawno pisałem na blogu o włączeniu Strings w Project Coin iw tym poście piszę o nowym Diamentowym Operatorze ( ).

Operator Diamond redukuje szczegółowość języka Java otaczającą elementy generyczne, umożliwiając kompilatorowi wnioskowanie o typach parametrów dla konstruktorów klas generycznych. Oryginalna propozycja dodania operatora diamentowego do języka Java została złożona w lutym 2009 roku i zawiera następujący prosty przykład:

Na przykład rozważmy następującą instrukcję przypisania:

Mapa anagrams = new HashMap ();

Jest to dość długie, więc można je zastąpić tym:

Mapa anagramy = new HashMap ();

Powyższy przykład przedstawiony w propozycji Jeremy'ego Mansona (który był jednym z pierwszych w odpowiedzi na zaproszenie do zgłaszania pomysłów na Project Coin) jest prosty, ale odpowiednio pokazuje, w jaki sposób Diamentowy Operator jest stosowany w JDK 7. Propozycja Mansona również wyjaśnia, dlaczego ten dodatek było pożądane:

Wymóg niepotrzebnego powielania parametrów typu

to zachęca nieszczęśnika

nadmiar statycznych metod fabrycznych, po prostu z powodu wnioskowania o typie

działa na wywołaniach metod.

Innymi słowy, dodanie Diamentowego Operatora JDK 7 Project Coin daje konstruktorom dostępne metody wnioskowania o typie. W przypadku metod wnioskowanie o typie jest wykonywane niejawnie, gdy opuszcza się jawną specyfikację typu parametru. Z drugiej strony, w przypadku tworzenia instancji operator diamentu musi być jawnie określony, aby „nakazać” kompilatorowi wywnioskowanie typu.

W swojej pierwotnej propozycji Manson wskazuje, że składnia bez specjalnego operatora diamentu nie może być używana do niejawnego wnioskowania o typach dla instancji, ponieważ „dla celów kompatybilności wstecznej, new Map () wskazuje na typ surowy i dlatego nie może być użyte dla typu wnioskowanie." Strona wnioskowania o typie w lekcji generycznej dotyczącej nauki języka Java w samouczkach języka Java zawiera sekcję „Wnioskowanie o typach i tworzenie wystąpień klas ogólnych”, która została już zaktualizowana, aby odzwierciedlić język Java SE 7. W tej sekcji opisano również, dlaczego należy określić operator, aby jawnie poinformować kompilator, aby używał wnioskowania o typie podczas tworzenia instancji:

Należy zauważyć, że aby skorzystać z automatycznego wnioskowania o typie podczas tworzenia instancji klasy ogólnej, należy określić operator rombu. W poniższym przykładzie kompilator generuje ostrzeżenie o niezaznaczonej konwersji, ponieważ konstruktor HashMap () odwołuje się do surowego typu HashMap, a nie do elementu Map rodzaj

W punkcie 24 („Eliminacja niesprawdzonych ostrzeżeń”) drugiej edycji efektywnej Javy Josh Bloch podkreśla pogrubioną czcionką: „Wyeliminuj wszystkie niezaznaczone ostrzeżenia, jakie możesz”. Bloch pokazuje przykład ostrzeżenia o niezaznaczonej konwersji, które pojawia się, gdy ktoś kompiluje kod używający typu surowego po prawej stronie deklaracji. Następna lista kodu zawiera kod, który doprowadzi do tego ostrzeżenia.

final Map
     
       statesToCities = new HashMap(); // raw! 
     

Następne dwa zrzuty ekranu przedstawiają odpowiedź kompilatora na powyższy wiersz kodu. Pierwszy obraz przedstawia komunikat, gdy nie ma włączonych ostrzeżeń -Xlint, a drugi przedstawia bardziej wyraźne ostrzeżenie, które występuje, gdy -Xlint:uncheckedzostanie przekazane jako argument javac.

Jeśli Java jest skuteczna , Bloch zwraca uwagę, że to konkretne niezaznaczone ostrzeżenie można łatwo rozwiązać, jawnie podając typ parametru w instancji klasy generycznej. Z JDK 7 będzie to jeszcze łatwiejsze! Zamiast konieczności dodawania jawnego tekstu z tymi nazwami typów, typy można wywnioskować w wielu przypadkach, a specyfikacja operatora diamentu informuje kompilator, aby dokonał tego wnioskowania, zamiast używać typu surowego.

Następna lista kodu Java zawiera uproszczone przykłady tych koncepcji. Istnieją metody, które demonstrują tworzenie instancji surowego zestawu, tworzenie instancji zestawu z jawną specyfikacją typu parametru oraz tworzenie instancji zestawu z typem parametru wywnioskowanym na podstawie specyfikacji operatora diamentu ( ).

package dustin.examples; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import static java.lang.System.out; /** * Very simple demonstration of JDK 7's/Project Coin's "Diamond Operator." */ public class DiamondOperatorDemo { /** Use of "raw" type. */ private static Set rawWithoutExplicitTyping() { final Set names = new HashSet(); addNames(names); return names; } /** Explicitly specifying generic class's instantiation parameter type. */ private static Set explicitTypingExplicitlySpecified() { final Set names = new HashSet(); addNames(names); return names; } /** * Inferring generic class's instantiation parameter type with JDK 7's * 'Diamond Operator.' */ private static Set explicitTypingInferredWithDiamond() { final Set names = new HashSet(); addNames(names); return names; } private static void addNames(final Set namesToAddTo) { namesToAddTo.add("Dustin"); namesToAddTo.add("Rett"); namesToAddTo.add("Homer"); } /** * Main executable function. */ public static void main(final String[] arguments) { out.println(rawWithoutExplicitTyping()); out.println(explicitTypingExplicitlySpecified()); out.println(explicitTypingInferredWithDiamond()); } } 

Gdy powyższy kod jest kompilowany, tylko „surowy” przypadek prowadzi do ostrzeżenia.

W tym momencie wnikliwe może być przyjrzenie się temu, co javap mówi nam o tych trzech metodach. Odbywa się to w tym przypadku za pomocą polecenia ( -vopcja verbose podaje wszystkie soczyste szczegóły i -pwyświetla te soczyste szczegóły dla privatemetod):

javap -v -p -classpath classes dustin.examples.DiamondOperatorDemo 

Ponieważ wszystkie te metody znajdowały się w jednej klasie, istnieje pojedynczy strumień danych wyjściowych dla całej klasy. Jednak, aby ułatwić ich porównywanie, wycinam i wklejam dane wyjściowe do formatu, który wyrównuje dane wyjściowe javap dla każdej metody względem siebie. Każda kolumna reprezentuje javapwynik dla jednej z metod. Zmieniłem kolor czcionki konkretnej metody na niebieski, aby wyróżnić się i oznaczyć dane wyjściowe tej kolumny.

Poza nazwami samych metod NIE ma różnicy w javapwynikach. Dzieje się tak, ponieważ wymazywanie typów ogólnych Java oznacza, że ​​różnicowanie na podstawie typu nie jest dostępne w czasie wykonywania. Samouczek Java na temat typów ogólnych zawiera stronę o nazwie Type Erasure, która wyjaśnia to:

Kompilator usuwa wszystkie informacje o faktycznym argumencie typu w czasie kompilacji.

Istnieje wymazywanie typów, aby nowy kod mógł nadal łączyć się ze starszym kodem. Używanie typu surowego z jakiegokolwiek innego powodu jest uważane za złą praktykę programistyczną i należy go unikać, gdy tylko jest to możliwe.

Jak przypomina nam powyższy cytat, wymazywanie oznacza, że ​​kodowanie bajtowe surowego typu nie różni się od jawnie wpisanego typu parametru, ale także zachęca programistów do nie używania typów surowych z wyjątkiem integracji ze starszym kodem.

Wniosek

Włączenie operatora diamentu ( ) w języku Java SE 7 oznacza, że ​​kod, który tworzy instancje klas ogólnych, może być mniej rozwlekły. Języki kodowania w ogóle, a Java w szczególności, zmierzają w kierunku takich pomysłów, jak konwencja nad konfiguracją, konfiguracja przez wyjątek i wnioskowanie tak często, jak to możliwe, zamiast wymagać wyraźnej specyfikacji. Języki z typami dynamicznymi są dobrze znane z wnioskowania o typie, ale nawet Java ze statycznym typowaniem może zrobić więcej niż robi, a operator diamentu jest tego przykładem.

Oryginalny post dostępny pod adresem //marxsoftware.blogspot.com/

Ta historia „JDK 7: Diamentowy operator” została pierwotnie opublikowana przez JavaWorld.