2010-10-01 11 views

risposta

23

Ci sono un sacco di modi diversi per raggiungere questo obiettivo , solo alcuni dei quali sono apparsi nelle risposte fino ad ora.

Metodo Uno: Dal java.util.HashMap ha il costruttore HashMap(Map<? extends K,? extends V> m), si potrebbe passare un Java Map valida. E si può fare questo banalmente con la Scala di utili JavaConversions:

scala> import scala.collection.JavaConversions._ 
import scala.collection.JavaConversions._ 

scala> val myMap = Map(1->"Hi",2->"Bye") 
myMap: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,Hi), (2,Bye)) 

scala> val jmap = new java.util.HashMap[Int,String](myMap) // Need explicit types 
jmap: java.util.HashMap[Int,String] = {1=Hi, 2=Bye} 

Gli aspetti negativi qui sono che si deve avere già una mappa Scala (un po 'uno spreco se si sta solo andando a creare un Java uno, forse), e che devi specificare i tipi. Ma è compatto e indolore.

Metodo due: In alternativa, è possibile creare un nuovo blocco di codice come istruzione di dichiarazione, in modo che non hanno nemmeno bisogno di avere a disposizione JavaConversions:

scala> val jmap2 = {    
    | val x = new java.util.HashMap[Int,String] 
    | for ((k,v) <- List(1->"Howdy",2->"partner")) x.put(k,v) 
    | x 
    | } 
jmap2: java.util.HashMap[Int,String] = {1=Howdy, 2=partner} 

Un po 'meno compatta, ma del tutto generale, e altrettanto efficiente (o inefficiente) come ci si preoccupa di farlo.

Metodo Tre: Inoltre, è possibile creare una sottoclasse anonima di HashMap fintanto che bene avere una sottoclasse (cioè .getClass non tornerà java.util.HashMap), e utilizzare l'inizializzatore per impostare i tuoi valori:

scala> val jmap3 = new java.util.HashMap[Int,String] { 
    | put(1,"Yo"); put(2,"bro") 
    | } 
jmap3: java.util.HashMap[Int,String] = {1=Yo, 2=bro} 

scala> jmap3.getClass.getName 
res0: java.lang.String = $anon$1 

scala> jmap3.getClass.getSuperclass.getName 
res1: java.lang.String = java.util.HashMap 

il rovescio della medaglia è, naturalmente, che si tratta di una sottoclasse di HashMap piuttosto che HashMap, ma è più compatta rispetto alla versione assegnazione-da-code-block dal momento che non c'è bisogno di assegnare la nuova mappa ad un val.

Metodo quattro: E infine, naturalmente, è possibile creare un metodo che fa quello che si vuole e chiamare invece:

scala> def newJHM[A,B](kv: Iterable[(A,B)]) = { 
    | val jhm = new java.util.HashMap[A,B] 
    | kv.foreach(i => jhm.put(i._1,i._2)) 
    | jhm         
    | }          
newJHM: [A,B](kv: Iterable[(A, B)])java.util.HashMap[A,B] 

scala> val jmap4 = newJHM(Seq(1->"Bye",2->"Now")) // Type inference now works 
jmap4: java.util.HashMap[Int,java.lang.String] = {1=Bye, 2=Now} 

Questo è poco meno compatto rispetto agli altri e ottiene i tipi corretta senza che tu debba specificarli, quindi può essere una scelta interessante se la stai facendo più di una volta.

P.S. Solo per divertimento, ho mostrato una varietà di modi per ottenere alcune coppie chiave-valore nella mappa, ma non sono specifiche per un determinato metodo (eccetto per il numero 1 che richiede una mappa). Mescola e abbina secondo le tue preferenze.

+0

Questa è un'ottima risposta. – eggonlegs

0

Tutti i metodi e i costruttori di java.util.HashMap sono a vostra disposizione, ovviamente, ma non forniscono un modo per inizializzare una mappa a meno che non ne abbia un altro per fornire i valori iniziali. Il più vicino probabilmente stai andando a ottenere è:

import java.util.HashMap 
val jhm = new HashMap[String, Int] 
«code to add key-value pairs to jhm» 
3

Sulla risposta di Randall, è possibile utilizzare JavaConversions per aiutare un po '.

import collection.JavaConversions.asMap 
import java.util.HashMap 
val jhm = new HashMap[Int,String](Map(1->"one", 2->"two")) 
8

Si potrebbe fare la mappa come una classe anonima, e fare l'inizializzazione come parte dell'istanza inizializzazione dell'oggetto.

import java.util.HashMap 
val jhm = new HashMap[String, Int](){ 
    put(key1, value1) 
    put(key2, value2) 
} 

Questo in realtà funziona altrettanto bene in Java (tranne che per richiedere doppie parentesi graffe {{}}), ma è molto più idiomatica a Scala.

+0

Non penso che ci sia qualcosa come l'inizializzazione statica di un oggetto. Suppongo che tu ti stia riferendo ad un inizializzatore di istanze, vero? –

+0

corretto. Editing –

+0

Tecnicamente, Scala non ha inizializzatori di istanza. Il codice che mostri sta eseguendo i metodi 'put' all'interno del * costruttore * per la classe interna anonima. –

0

Per rendere qualcosa riutilizzabile, sarebbe possibile creare un nuovo sottotipo "Mappa" solo per la sintassi di inizializzazione.

Potrebbe funzionare qualcosa come questo (sto ignorando i generici perché io non li uso regolarmente e avrei probabilmente ottenere qualcosa che non va):

HashMap hm=new HashMap(
    new InitMap(
     new String[]{"one", "two", "three"}, 
     new int[] { 1 , 2 , 3 }; 
    ) 
); 

Non ci sarebbe più codice coinvolti nel InitMap classe ma sarebbe riutilizzabile e abbastanza diretto (mi piace molto la sintassi di inizializzazione degli array per questo genere di cose).

Pensandoci, la classe InitMap non sarebbe troppo difficile. Probabilmente vorresti capire quali metodi sono stati chiamati e implementarli. È probabile che chiamerebbe solo i metodi KeySet e EntrySet.

Naturalmente a questo ritmo si potrebbe semplice creare un metodo di supporto che ha preso i due array e ha restituito un HashMap o estendere HashMap e aggiungere un nuovo costruttore ...