Programmering

JDK 7: Diamantoperatøren

Project Coin giver adskillige "små sprogforbedringer" som en delmængde af de nye JDK 7-funktioner. Jeg bloggede for nylig på Project Coin, der tænder for strenge, og i dette indlæg skriver jeg om den nye Diamond Operator ().

Diamond Operator reducerer noget af Javas bredhed omkring generiske gener ved at lade kompilatoren udlede parametertyper til konstruktører af generiske klasser. Det oprindelige forslag om at tilføje Diamond Operator til Java-sproget blev fremsat i februar 2009 og inkluderer dette enkle eksempel:

Overvej f.eks. Følgende opgaveerklæring:

Kort anagrammer = nyt HashMap();

Dette er ret langvarigt, så det kan erstattes med dette:

Kort anagrammer = nyt HashMap ();

Ovenstående eksempel givet i Jeremy Mansons forslag (som var et af de første som svar på en opfordring til Project Coin-ideer) er simpelt, men viser tilstrækkeligt, hvordan diamantoperatøren anvendes i JDK 7. Mansons forslag giver også væsentlig betydning for, hvorfor denne tilføjelse var ønskeligt:

Kravet om, at typeparametre duplikeres unødigt som

dette tilskynder en ulykkelig

overvægt af statiske fabriksmetoder, simpelthen fordi type inferens

arbejder på metodeopkald.

Med andre ord, JDK 7 Project Coin-tilføjelsen af ​​en diamantoperatør bringer typeforhold til konstruktører, der har været tilgængelige med metoder. Med metoder udføres typeafledning implicit, når man forlader den eksplicitte parametertypespecifikation. Med instantiering skal derimod diamantoperatøren specificeres eksplicit for at "fortælle" kompilatoren at udlede typen.

I sit oprindelige forslag påpeger Manson, at syntaks uden en speciel diamantoperatør ikke kunne bruges til implicit at udlede typer til instantieringer, fordi "med henblik på bagudkompatibilitet angiver nyt kort () en rå type og derfor ikke kan bruges til type slutning. " Siden Type Inference i Generics Lesson of the Learning the Java Language trail i Java Tutorials inkluderer et afsnit kaldet "Type Inference and Instantiation of Generic Classes", der allerede er blevet opdateret til at afspejle Java SE 7. Dette afsnit beskriver også hvorfor specialet operatør skal specificeres for eksplicit at informere kompilatoren om at bruge typeinferens ved instantiering:

Bemærk, at du skal angive diamantoperatøren for at drage fordel af automatisk typeinferens under generisk klasseinstansiering. I det følgende eksempel genererer compileren en ikke-markeret konverteringsadvarsel, fordi HashMap () -konstruktøren henviser til HashMap-rå typen, ikke kortet type

I punkt 24 ("Eliminer ukontrollerede advarsler") i anden udgave af effektiv Java understreger Josh Bloch i fremhævet tekst, "Fjern enhver ukontrolleret advarsel, du kan." Bloch viser et eksempel på den ukontrollerede konverteringsadvarsel, der opstår, når man kompilerer kode, der bruger en rå type på højre side af en erklæring. Den næste kodeliste viser kode, der vil føre til denne advarsel.

endelige kort statesToCities = ny HashMap (); // rå! 

De næste to skærmbilleder viser kompilatorens svar på ovenstående kodelinje. Det første billede viser beskeden, når der ikke er aktiveret -Xlint-advarsler, og det andet viser den mere eksplicitte advarsel, der opstår når -Xlint: ikke markeret leveres som et argument til javac.

Hvis Effektiv Java, Bloch påpeger, at denne særlige ukontrollerede advarsel er let at adressere ved eksplicit at angive parametertypen til instantiering af den generiske klasse. Med JDK 7 bliver dette endnu lettere! I stedet for at skulle tilføje den eksplicitte tekst med disse typenavne, kan typerne udledes i mange tilfælde, og specifikationen af ​​diamantoperatøren fortæller kompilatoren at foretage denne slutning i stedet for at bruge den rå type.

Den næste Java-kodeliste giver forenklede eksempler på disse begreber. Der er metoder, der demonstrerer instantiering af et råt sæt, instantiering af et sæt med eksplicit specifikation af dets parametertype og instantiering af et sæt med afledt parametertype på grund af specifikation af diamantoperatøren ().

pakke dustin. eksempler; importere java.util.HashMap; importere java.util.HashSet; importere java.util.Map; importere java.util.Set; importere statisk java.lang.System.out; / ** * Meget enkel demonstration af JDK 7's / Project Coin's "Diamond Operator." * / public class DiamondOperatorDemo {/ ** Brug af "rå" type. * / privat statisk sæt rawWithoutExplicitTyping () {final Set names = new HashSet (); addNames (navne); returnere navne; } / ** Angiver eksplicit generisk klasses instantieringsparametertype. * / privat statisk sæt explicitTypingExplicitlySpecified () {final Set names = new HashSet (); addNames (navne); returnere navne; } / ** * Udleder generisk klasses instantieringsparametertype med JDK 7's * 'Diamond Operator.' * / private static Set explicitTypingInferredWithDiamond () {final Set names = new HashSet (); addNames (navne); returnere navne; } private statiske ugyldige addNames (final Set namesToAddTo) {namesToAddTo.add ("Dustin"); namesToAddTo.add ("Rett"); namesToAddTo.add ("Homer"); } / ** * Hovedfunktionsfunktion. * / public static void main (final String [] argumenter) {out.println (rawWithoutExplicitTyping ()); out.println (explicitTypingExplicitlySpecified ()); out.println (explicitTypingInferredWithDiamond ()); }} 

Når ovenstående kode er kompileret, er det kun den "rå" sag, der fører til en advarsel.

På dette tidspunkt kan det være indsigtsfuldt at se på, hvad javap fortæller os om disse tre metoder. Dette gøres i dette tilfælde med kommandoen (-v mulighed for verbose giver alle de saftige detaljer og -p viser disse saftige detaljer til privat metoder):

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

Fordi disse metoder alle var i en enkelt klasse, er der en enkelt strøm af output for hele klassen. For at gøre det lettere at sammenligne dem har jeg dog klippet og indsat output i et format, der justerer javap-output for hver metode mod hinanden. Hver kolonne repræsenterer javap output til en af ​​metoderne. Jeg har ændret skrifttypefarven på den bestemte metode til blå for at få den til at skille sig ud og mærke kolonnens output.

Bortset fra navnene på selve metoderne er der INGEN forskel i javap produktion. Dette skyldes, at Java generics type sletning betyder, at differentiering baseret på type ikke er tilgængelig under kørsel. Java-vejledningen om generik inkluderer en side kaldet Type Erasure, der forklarer dette:

Compileren fjerner alle oplysninger om det aktuelle typeargument på kompileringstidspunktet.

Type sletning findes, så ny kode kan fortsætte med at grænseflade med ældre kode. Brug af en rå type af anden grund betragtes som dårlig programmeringspraksis og bør undgås, når det er muligt.

Som citatet ovenfor minder os om, betyder sletning, at at bytekode en rå type ikke er anderledes end en eksplicit indtastet parametertype, men også tilskynder udviklere til ikke at bruge rå typer undtagen at integrere med ældre kode.

Konklusion

Inkluderingen af ​​diamantoperatøren () i Java SE 7 betyder, at kode, der instanterer generiske klasser, kan være mindre detaljeret. Kodningssprog generelt og Java i særdeleshed bevæger sig mod ideer som konvention over konfiguration, konfiguration undtagelsesvis og udleder ting så ofte som muligt i stedet for at kræve eksplicit specifikation. Dynamisk typede sprog er velkendte for typeinferens, men selv statisk typet Java kan gøre mere af dette end det gør, og diamantoperatøren er et eksempel på dette.

Oprindelig udstationering tilgængelig på //marxsoftware.blogspot.com/

Denne historie, "JDK 7: The Diamond Operator" blev oprindeligt udgivet af JavaWorld.