Programování

JDK 7: Diamantový operátor

Project Coin poskytuje řadu „malých jazykových vylepšení“ jako podmnožinu nových funkcí JDK 7. Nedávno jsem blogoval o tom, jak Project Coin zapíná Strings, a v tomto příspěvku píšu o novém Diamond Operator ().

Diamantový operátor snižuje některé výřečnosti Javy obklopující obecné typy tím, že má kompilátor odvodit typy parametrů pro konstruktory obecných tříd. Původní návrh na přidání operátora Diamond do jazyka Java byl vytvořen v únoru 2009 a zahrnuje tento jednoduchý příklad:

Zvažte například následující příkaz přiřazení:

Mapa anagramy = nový HashMap();

To je poměrně zdlouhavé, takže jej lze nahradit tímto:

Mapa anagramy = nový HashMap ();

Výše uvedený příklad poskytnutý v návrhu Jeremyho Mansona (který byl jedním z prvních v reakci na výzvu k získání nápadů na Project Coin) je jednoduchý, ale dostatečně ukazuje, jak je diamantový operátor aplikován v JDK 7. Mansonův návrh také významně vysvětluje, proč toto doplnění bylo žádoucí:

Požadavek duplikování parametrů typu se zbytečně líbí

to povzbuzuje nešťastníka

nadbytek statických továrních metod, jednoduše proto, že odvození typu

pracuje na vyvolání metod.

Jinými slovy, přidání diamantového operátoru JDK 7 Project Coin přináší odvození typu do konstruktorů, které byly k dispozici s metodami. U metod se odvození typu implicitně provádí, když jeden opustí specifikaci explicitního typu parametru. Na druhé straně s instancí musí být operátor diamantu specifikován explicitně, aby "řekl" kompilátoru, aby odvodil typ.

Ve svém původním návrhu Manson poukazuje na to, že syntaxi bez speciálního operátoru diamantu nelze použít k implicitnímu odvození typů pro instance, protože „pro účely zpětné kompatibility nový Map () označuje hrubý typ, a proto jej nelze použít pro typ odvození." Stránka Type Inference v lekci Generics of the Learning the Java Language trail of the Java Tutorials includes a section called "Type Inference and Instantiation of Generic Classes" which has already been updated to reflect Java SE 7. This section also explains why the special operátor musí být zadán, aby explicitně informoval kompilátor, aby použil instanci typu na instanci:

Všimněte si, že chcete-li využít výhody automatického odvození typu během instance obecné třídy, musíte zadat operátor diamantu. V následujícím příkladu kompilátor generuje nekontrolované upozornění na převod, protože konstruktor HashMap () odkazuje na surový typ HashMap, nikoli Map typ

V položce 24 („Odstranit nekontrolovaná varování“) druhého vydání Effective Java zdůrazňuje Josh Bloch v tučně text „Odstraňte všechna nezaškrtnutá varování, která můžete.“ Bloch ukazuje příklad nekontrolovaného upozornění na převod, ke kterému dojde, když jeden zkompiluje kód, který používá surový typ na pravé straně deklarace. Následující výpis kódu ukazuje kód, který povede k tomuto varování.

závěrečná mapa statesToCities = new HashMap (); // drsný! 

Další dva snímky obrazovky ukazují odpověď kompilátoru na výše uvedený řádek kódu. První obrázek zobrazuje zprávu, když nejsou povolena žádná varování -Xlint, a druhý ukazuje explicitnější varování, které nastane, když -Xlint: nezaškrtnuto je poskytován jako argument pro javac.

Li Efektivní JavaBloch poukazuje na to, že toto konkrétní nekontrolované varování lze snadno vyřešit explicitním poskytnutím typu parametru pro instanci generické třídy. S JDK 7 to bude ještě jednodušší! Místo toho, aby bylo nutné přidat explicitní text s těmito názvy typů, lze typy v mnoha případech odvodit a specifikace operátoru diamantu říká kompilátoru, aby provedl tento závěr spíše než pomocí surového typu.

Následující seznam kódů Java poskytuje zjednodušující příklady těchto konceptů. Existují metody, které ukazují instanci surové sady, instanci sady s explicitní specifikací jejího typu parametru a instanci sady s typem parametru odvozenou z důvodu specifikace operátoru diamantu ().

příklady zásilky; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; importovat statický java.lang.System.out; / ** * Velmi jednoduchá ukázka „diamantového operátora“ JDK 7 / Project Coin. * / veřejná třída DiamondOperatorDemo {/ ** Použití typu „raw“. * / private static Set rawWithoutExplicitTyping () {final Set names = new HashSet (); addNames (jména); návratová jména; } / ** Explicitně určující typ parametru instance instance generické třídy. * / private static Set explicitTypingExplicitlySpecified () {final names set = new HashSet (); addNames (jména); návratová jména; } / ** * Odvození typu parametru instance instance generické třídy pomocí JDK 7 * 'Diamond Operator.' * / private static Set explicitTypingInferenceWithDiamond () {final Set names = new HashSet (); addNames (jména); návratová jména; } private static void addNames (final Set namesToAddTo) {namesToAddTo.add ("Dustin"); namesToAddTo.add ("Rett"); namesToAddTo.add ("Homer"); } / ** * Hlavní spustitelná funkce. * / public static void main (final String [] argumenty) {out.println (rawWithoutExplicitTyping ()); out.println (explicitTypingExplicitlySpecified ()); out.println (explicitTypingInferenceWithDiamond ()); }} 

Když je zkompilován výše uvedený kód, pouze "raw" případ vede k varování.

V tomto okamžiku může být rozumné podívat se na to, co nám o těchto třech metodách říká javap. To se v tomto případě provádí příkazem (-proti možnost verbose poskytuje všechny šťavnaté detaily a -p zobrazí tyto šťavnaté podrobnosti pro soukromé metody):

javap -v -p -classpath třídy dustin.examples.DiamondOperatorDemo 

Protože tyto metody byly všechny v jedné třídě, existuje jediný proud výstupu pro celou třídu. Aby však bylo snazší je porovnat, výstup jsem vyjmul a vložil do formátu, který srovnává výstup javapu pro každou metodu proti sobě. Každý sloupec představuje javap výstup pro jednu z metod. Změnil jsem barvu písma konkrétní metody na modrou, aby vynikla a označila výstup tohoto sloupce.

Kromě názvů samotných metod není v javap výstup. Je to proto, že mazání generických typů Java znamená, že diferenciace podle typu není za běhu k dispozici. Výukový program Java pro generika obsahuje stránku nazvanou Vymazání typu, která vysvětluje toto:

Kompilátor odebere všechny informace o argumentu skutečného typu v době kompilace.

Existuje vymazání typu, aby mohl nový kód pokračovat v rozhraní se starším kódem. Použití surového typu z jakéhokoli jiného důvodu je považováno za špatnou programovací praxi a je třeba se mu vyhnout, kdykoli je to možné.

Jak nám výše uvedená citace připomíná, mazání znamená, že pro bytecode se surový typ neliší od explicitně zadaného typu parametru, ale také podporuje vývojáře, aby nepoužívali surové typy kromě integrace se starým kódem.

Závěr

Zahrnutí provozovatele diamantů () v prostředí Java SE 7 znamená, že kód, který vytváří instanci obecných tříd, může být méně podrobný. Programovací jazyky obecně, a zejména Java, směřují k myšlenkám, jako je konvence nad konfigurací, konfigurace podle výjimky a odvozování věcí tak často, jak je to možné, spíše než vyžadovat explicitní specifikaci. Jazyky s dynamickým typem jsou dobře známy pro odvozování typů, ale i Java se statickým typem toho dokáže více, než činí, a příkladem je diamantový operátor.

Původní zveřejnění příspěvků je k dispozici na //marxsoftware.blogspot.com/

Tento příběh „JDK 7: The Diamond Operator“ byl původně publikován společností JavaWorld.