JDK 7: Dijamantni operater

Project Coin nudi brojna „mala jezična poboljšanja“ kao podskup novih značajki JDK 7. Nedavno sam blogovao o prebacivanju žica na Project Coin i u ovom postu pišem o novom Diamond Operatoru ( ).

Diamond Operator smanjuje neke od višejezičnih Java-ovih generičkih generacija tako što prevodilac zaključuje tipove parametara za konstruktore generičkih klasa. Izvorni prijedlog za dodavanje Operatora dijamanata na jezik Java dan je u veljači 2009. godine i uključuje ovaj jednostavan primjer:

Na primjer, razmotrite sljedeću izjavu o dodjeli:

Karta anagrami = nova HashMap ();

Ovo je prilično dugo, pa se može zamijeniti ovim:

Karta anagrami = novi HashMap ();

Gornji primjer naveden u prijedlogu Jeremyja Mansona (koji je bio jedan od prvih kao odgovor na poziv za ideje za projektne novčiće) jednostavan je, ali adekvatno pokazuje kako se Dijamantni operater primjenjuje u JDK 7. Mansonov prijedlog također daje značajne razloge zašto ovaj dodatak bilo poželjno:

Zahtjev da se parametri tipa dupliciraju nepotrebno sviđa se

ovo potiče nesretnika

prekomjernost statičkih tvorničkih metoda, jednostavno zbog zaključivanja tipa

radi na zazivima metoda.

Drugim riječima, dodatak dijamantskog operatora JDK 7 Project Coin donosi konstrukcijskim zaključcima tip koji je dostupan s metodama. S metodama se zaključivanje tipa implicitno vrši kada se izostavi eksplicitna specifikacija tipa parametra. S instancijom, s druge strane, dijamantni operator mora biti izričito naveden kako bi "rekao" sastavljaču da zaključi o tipu.

U svom izvornom prijedlogu Manson ističe da se sintaksa bez posebnog dijamantskog operatora ne bi mogla koristiti za implicitno zaključivanje tipova za instancije jer "u svrhu povratne kompatibilnosti nova Map () označava neobrađeni tip, pa se stoga ne može koristiti za tip zaključak." Stranica zaključka o tipovima Lekcije o generičkom učenju traga za učenje Java jezika u Java Vodičima uključuje odjeljak pod nazivom "Izvođenje tipa i instantacija generičkih klasa" koji je već ažuriran kako bi odražavao Java SE 7. Ovaj odjeljak također opisuje zašto posebni mora biti naveden operator da izričito obavijesti prevoditelj da koristi zaključivanje tipa o instanciranju:

Imajte na umu da da biste iskoristili prednost automatskog zaključivanja tipa tijekom instancije generičke klase, morate navesti operator dijamanta. U sljedećem primjeru, prevodilac generira neprovjereno upozorenje o pretvorbi jer se konstruktor HashMap () odnosi na HashMap neobrađeni tip, a ne na Map tip

U stavci 24 ("Uklanjanje neprovjerenih upozorenja") Drugog izdanja učinkovite Jave, Josh Bloch podebljanim tekstom naglašava : "Uklonite svako neprovjereno upozorenje koje možete." Bloch prikazuje primjer neprovjerenog upozorenja o pretvorbi koje se javlja kada se kompilira kôd koji koristi sirovi tip s desne strane deklaracije. Sljedeći popis kodova prikazuje kod koji će dovesti do ovog upozorenja.

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

Sljedeće dvije snimke zaslona prikazuju odgovor prevoditelja na gornji redak koda. Prva slika prikazuje poruku kada nisu omogućena upozorenja -Xlint, a druga prikazuje eksplicitnije upozorenje koje se javlja kada -Xlint:uncheckedje dato kao argument za javac.

Ako je efektivna Java , Bloch ističe da je ovo posebno neprovjereno upozorenje lako adresirati izričitim pružanjem tipa parametra instanciranju generičke klase. S JDK 7 to će biti još lakše! Umjesto potrebe za dodavanjem eksplicitnog teksta s tim imenima tipova, tipovi se mogu izvesti u mnogim slučajevima, a specifikacija operatora dijamanata govori sastavljaču da napravi taj zaključak umjesto da koristi sirovi tip.

Sljedeći popis Java koda pruža pojednostavljene primjere tih koncepata. Postoje metode koje pokazuju instanciju sirovog skupa, instanciju skupa s izričitom specifikacijom njegove vrste parametra i instanciju skupa s vrstom parametra koja se izvodi zbog specifikacije dijamantskog operatora ( ).

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()); } } 

Kad je gornji kod kompiliran, samo "sirovi" slučaj dovodi do upozorenja.

U ovom trenutku može biti pronicljivo pogledati što nam javap govori o ove tri metode. To se u ovom slučaju radi naredbom ( -vopcija za opširno daje sve sočne detalje i -pprikazuje ove sočne detalje za privatemetode):

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

Budući da su sve metode bile u jednoj klasi, postoji jedan tok rezultata za cijelu klasu. Međutim, kako bih ih olakšao usporedbu, izrezao sam i zalijepio izlaz u format koji usklađuje javap izlaz za svaku metodu. Svaki stupac predstavlja javapizlaz za jednu od metoda. Promijenio sam boju fonta određene metode u plavu kako bih se istaknuo i označio izlaz tog stupca.

Osim imena samih metoda, NEMA razlike u javaprezultatima. To je zato što brisanje generičkog tipa Java znači da razlikovanje na temelju tipa nije dostupno u vrijeme izvođenja. Java Tutorial o generičkim lijekovima uključuje stranicu koja se naziva Type Erasure koja objašnjava ovo:

Prevoditelj uklanja sve informacije o stvarnom argumentu tipa u vrijeme sastavljanja.

Izbris tipa postoji da bi novi kôd mogao nastaviti surađivati ​​sa naslijeđenim kodom. Korištenje sirove vrste iz bilo kojeg drugog razloga smatra se lošom programskom praksom i treba je izbjegavati kad god je to moguće.

Kao što nas podsjeća gornji citat, brisanje znači da se bytecode sirovog tipa ne razlikuje od eksplicitno upisanog tipa parametra, ali također potiče programere da ne koriste sirove tipove, osim za integraciju s naslijeđenim kodom.

Zaključak

Uključivanje dijamantskog operatora ( ) u Java SE 7 znači da kod koji instancira generičke klase može biti manje opširan. Kodirani jezici općenito, a posebno Java, kreću se prema idejama poput konvencije oko konfiguracije, konfiguracije iznimkom i zaključivanja stvari što je češće moguće, umjesto da zahtijevaju eksplicitnu specifikaciju. Dinamički tipizirani jezici dobro su poznati po zaključivanju tipova, ali čak i statički upisana Java može to učiniti više nego što čini, a dijamantski operater je primjer za to.

Originalno objavljivanje dostupno na //marxsoftware.blogspot.com/

Ovu priču "JDK 7: Dijamantni operater" izvorno je objavio JavaWorld.