JDK 7: The Diamond Operator

Project Coin fornisce numerosi "piccoli miglioramenti del linguaggio" come sottoinsieme delle nuove funzionalità di JDK 7. Recentemente ho scritto sul blog di Project Coin sull'accensione delle stringhe e in questo post scrivo del nuovo Diamond Operator ( ).

L'operatore Diamond riduce parte della verbosità di Java che circonda i generici facendo in modo che il compilatore deduca i tipi di parametri per i costruttori di classi generiche. La proposta originale per l'aggiunta del Diamond Operator al linguaggio Java è stata fatta nel febbraio 2009 e include questo semplice esempio:

Ad esempio, considera la seguente dichiarazione di assegnazione:

Carta geografica anagrammi = nuova HashMap ();

Questo è piuttosto lungo, quindi può essere sostituito con questo:

Carta geografica anagrammi = new HashMap ();

L'esempio sopra fornito nella proposta di Jeremy Manson (che è stato uno dei primi in risposta a un invito a presentare idee per Project Coin) è semplice, ma dimostra adeguatamente come il Diamond Operator viene applicato in JDK 7. La proposta di Manson fornisce anche un significativo motivo per cui questa aggiunta era desiderabile:

Il requisito che i parametri di tipo vengano duplicati inutilmente come

questo incoraggia uno sfortunato

sovrabbondanza di metodi factory statici, semplicemente perché inferenza di tipo

funziona su invocazioni di metodi.

In altre parole, l'aggiunta JDK 7 Project Coin di un Diamond Operator porta l'inferenza del tipo ai costruttori che è stata disponibile con i metodi. Con i metodi l'inferenza del tipo viene eseguita implicitamente quando si tralascia la specifica del tipo di parametro esplicito. Con la creazione di istanze, d'altra parte, l'operatore diamante deve essere specificato esplicitamente per "dire" al compilatore di dedurre il tipo.

Nella sua proposta originale, Manson sottolinea che la sintassi senza uno speciale operatore a diamante non potrebbe essere utilizzata per dedurre implicitamente i tipi per le istanze perché "ai fini della compatibilità con le versioni precedenti, new Map () indica un tipo grezzo, e quindi non può essere utilizzato per il tipo inferenza." La pagina di inferenza del tipo della lezione generica dell'apprendimento del linguaggio Java trail dei tutorial Java include una sezione chiamata "inferenza del tipo e istanziazione di classi generiche" che è già stata aggiornata per riflettere Java SE 7. Questa sezione descrive anche perché lo speciale L'operatore deve essere specificato per informare esplicitamente il compilatore di utilizzare l'inferenza del tipo sull'istanza:

Si noti che per sfruttare l'inferenza automatica del tipo durante l'istanza di classi generiche, è necessario specificare l'operatore romboidale. Nell'esempio seguente, il compilatore genera un avviso di conversione non controllato perché il costruttore HashMap () fa riferimento al tipo raw HashMap, non al Map genere

Nell'articolo 24 ("Elimina avvisi non controllati") della seconda edizione di Java effettivo, Josh Bloch enfatizza in grassetto "Elimina ogni avviso non controllato che puoi". Bloch mostra un esempio dell'avviso di conversione non controllato che si verifica quando si compila codice che utilizza un tipo non elaborato sul lato destro di una dichiarazione. Il listato di codice successivo mostra il codice che porterà a questo avviso.

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

Le successive due istantanee dello schermo mostrano la risposta del compilatore alla riga di codice precedente. La prima immagine mostra il messaggio quando non ci sono avvisi -Xlint abilitati e la seconda mostra l'avviso più esplicito che si verifica quando -Xlint:uncheckedviene fornito come argomento a javac.

Se Java efficace , Bloch sottolinea che questo particolare avviso non controllato è facile da affrontare fornendo esplicitamente il tipo di parametro all'istanza della classe generica. Con JDK 7, questo sarà ancora più facile! Invece di dover aggiungere il testo esplicito con questi nomi di tipo, i tipi possono essere dedotti in molti casi e la specifica dell'operatore diamante dice al compilatore di fare questa inferenza piuttosto che usare il tipo grezzo.

Il successivo listato di codice Java fornisce esempi semplicistici di questi concetti. Esistono metodi che dimostrano l'istanziazione di un Set grezzo, l'istanziazione di un Set con specifica esplicita del suo tipo di parametro e l'istanziazione di un Set con tipo di parametro dedotto a causa della specifica dell'operatore diamante ( ).

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

Quando il codice precedente viene compilato, solo il caso "grezzo" porta a un avviso.

A questo punto, può essere utile guardare cosa ci dice javap su questi tre metodi. Questo viene fatto in questo caso con il comando (l' -vopzione per verbose fornisce tutti i dettagli succosi e -pvisualizza questi dettagli succosi per i privatemetodi):

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

Poiché questi metodi erano tutti in una singola classe, esiste un unico flusso di output per l'intera classe. Tuttavia, per semplificare il confronto, ho tagliato e incollato l'output in un formato che allinea l'output javap per ciascun metodo l'uno contro l'altro. Ogni colonna rappresenta l' javapoutput per uno dei metodi. Ho cambiato il colore del carattere del particolare metodo in blu per farlo risaltare ed etichettare l'output di quella colonna.

A parte i nomi dei metodi stessi, NON c'è differenza javapnell'output. Questo perché la cancellazione dei tipi generici di Java significa che la differenziazione basata sul tipo non è disponibile in fase di esecuzione. Il Tutorial Java su Generics include una pagina chiamata Type Erasure che spiega questo:

Il compilatore rimuove tutte le informazioni sull'argomento di tipo effettivo in fase di compilazione.

Esiste la cancellazione del tipo in modo che il nuovo codice possa continuare a interfacciarsi con il codice legacy. L'uso di un tipo grezzo per qualsiasi altro motivo è considerato una cattiva pratica di programmazione e dovrebbe essere evitato quando possibile.

Come ci ricorda la citazione sopra, la cancellazione significa che bytecode un tipo grezzo non è diverso da un tipo di parametro tipizzato in modo esplicito, ma incoraggia anche gli sviluppatori a non utilizzare tipi grezzi tranne che per l'integrazione con codice legacy.

Conclusione

L'inclusione dell'operatore diamante ( ) in Java SE 7 significa che il codice che istanzia classi generiche può essere meno dettagliato. I linguaggi di codifica in generale, e Java in particolare, si stanno muovendo verso idee come la convenzione sulla configurazione, la configurazione per eccezione, e inferire le cose il più spesso possibile piuttosto che richiedere una specifica esplicita. I linguaggi tipizzati dinamicamente sono ben noti per l'inferenza del tipo, ma anche Java tipizzato staticamente può fare più di quanto non faccia e l'operatore rombo ne è un esempio.

Pubblicazione originale disponibile su //marxsoftware.blogspot.com/

Questa storia, "JDK 7: The Diamond Operator" è stata originariamente pubblicata da JavaWorld.