2009-06-22 9 views
14

Un'API Java restituisce un java.util.Map<java.lang.String,java.lang.Boolean>;. Vorrei mettere che in un Map[String,Boolean]Come convertire da java.util.Map a una mappa Scala

Quindi immaginate abbiamo:

var scalaMap : Map[String,Boolean] = Map.empty 
val javaMap = new JavaClass().map() // Returns java.util.Map<java.lang.String,java.lang.Boolean> 

Non si può fare Map.empty ++ javaMap, perché il metodo ++ non conosce le mappe Java. Ho provato:

scalaMap = Map.empty ++ new collection.jcl.MapWrapper[String,Boolean] { 
    override def underlying = javaMap 
} 

e:

scalaMap = Map.empty ++ new collection.jcl.MapWrapper[java.lang.String,java.lang.Boolean] { 
    override def underlying = javaMap 
    } 

Questi entrambi non riescono a compilare, a causa dei farmaci generici - java.lang.String non è la stessa come String Scala.

C'è un buon modo per farlo, a meno di copiare manualmente la mappa?

EDIT: Grazie, tutte le buone risposte, ho imparato molto da tutti loro. Tuttavia, ho commesso un errore pubblicando qui un problema più semplice di quello che effettivamente ho. Quindi, se mi permettete, io generalizzare la questione - ciò che l'API restituisce in realtà è

java.util.Map<java.lang.String, java.util.Map<SomeJavaEnum,java.lang.String>> 

E ho bisogno di spostare questo alla mappa [String, mappa [SomeJavaEnum, String]]

E ' probabilmente non sembra una complicazione eccessiva, ma aggiunge un ulteriore livello di cancellazione dei caratteri, e l'unico modo in cui ho trovato di spostarlo in una mappa di Scala è stato copiarlo in profondità (utilizzando alcune delle tecniche che hai suggerito di seguito). Qualche suggerimento? Ho risolto il mio problema definendo una conversione implicita per i miei tipi esatti, quindi almeno la bruttezza è nascosta nel suo tratto, ma comunque mi sento un po 'goffo nel copiare il tutto.

+0

Mi piace molto la risposta Conversions che ho ricevuto dal gruppo scala-user. Ho solo bisogno di verificare se funziona ... Ma ora è troppo tardi, quindi posteremo presto ... – George

risposta

2

useJavaMap.scala

import test._ 
import java.lang.Boolean 
import java.util.{Map => JavaMap} 
import collection.jcl.MapWrapper 

object useJavaMap { 
    def main(args: Array[String]) { 
    var scalaMap : Map[String, Boolean] = Map.empty 
    scalaMap = toMap(test.testing()) 
    println(scalaMap) 
    } 

    def toMap[K, E](m: JavaMap[K, E]): Map[K, E] = { 
    Map.empty ++ new MapWrapper[K, E]() { 
     def underlying = m 
    } 
    } 
} 

test/test.java

package test; 

import java.util.*; 

public class test { 
    public static Map<String, Boolean> testing() { 
     Map<String, Boolean> x = new HashMap<String, Boolean>(); 
     x.put("Test",Boolean.FALSE); 
     return x; 
    } 
    private test() {} 
} 

Commandline

javac test\test.java 
scalac useJavaMap.scala 
scala useJavaMap 
> Map(Test -> false) 
+0

Nessuno dei due lavori, temo. Queste sono classi generiche - Map [String, Boolean] non è la stessa di Map [java.lang.String, java.lang.Boolean], quindi ottieni: type mismatch; trovato: java.lang.Object con scala.collection.jcl.MapWrapper [String, Boolean] \t {...} richiesto: mappa [String, Boolean] (utilizzando il primo esempio) – George

+0

avuto il tempo di provare. campione completo fornito – jitter

+0

Grazie, 'Map.empty ++ JMapWrapper [K, V] (myJavaMap)' è quello che voglio! –

0

Penso di avere una risposta parziale ...

Se si converte la mappa java in una scala mappa con i tipi java. È quindi possibile mappare a una mappa scala di tipi di Scala:

val javaMap = new java.util.TreeMap[java.lang.String, java.lang.Boolean] 
val temp = new collection.jcl.MapWrapper[java.lang.String,java.lang.Boolean] { 
    override def underlying = javaMap 
} 
val scalaMap = temp.map{ 
    case (k, v) => (k.asInstanceOf[String] -> v.asInstanceOf[Boolean]) 
} 

Il difetto di questo piano è che il tipo di scalaMap è Iterable [(java.lang.String, booleano)] non è una mappa. Mi sento così vicino, qualcuno più intelligente di me può aggiustare l'ultima affermazione per fare in modo che funzioni ?!

6

A Scala String è un java.lang.Stringma a Scala Booleannon è un java.lang.Boolean.Di qui le seguenti opere:

import collection.jcl.Conversions._ 
import collection.mutable.{Map => MMap} 
import java.util.Collections._ 
import java.util.{Map => JMap} 

val jm: JMap[String, java.lang.Boolean] = singletonMap("HELLO", java.lang.Boolean.TRUE) 

val sm: MMap[String, java.lang.Boolean] = jm //COMPILES FINE 

Ma il problema è ancora il problema con la differenza Boolean. Dovrete "piegare" la mappa di Java in scala uno: provi ad usare il tipo Scala Boolean:

val sm: MMap[String, Boolean] = collection.mutable.Map.empty + ("WORLD" -> false) 
val mm = (sm /: jm) { (s, t2) => s + (t2._1 -> t2._2.booleanValue) } 

Poi mm è una mappa scala contenente il contenuto della mappa scala originale più quello che era nel Java map

+0

In realtà, la tua risposta si trasforma in mappa mutevole, mentre l'autore ha chiesto immutabile. –

11

Almeno con Scala 2.9.2 c'è un modo più semplice con le conversioni di raccolte: importare "import collection.JavaConversions._" e usare "toMap".

Esempio:

// show with Java Map: 

scala> import java.util.{Map=>JMap} 
scala> val jenv: JMap[String,String] = System.getenv() 
jenv: java.util.Map[String,String] = {TERM=xterm, ANT_OPTS=-Xmx512m ...} 

scala> jenv.keySet() 
res1: java.util.Set[String] = [TERM, ANT_OPTS...] 

// Now with Scala Map: 

scala> import collection.JavaConversions._ 
scala> val env: Map[String,String] = System.getenv.toMap // <--- TADA <--- 
env: Map[String,String] = Map(ANT_OPTS -> -Xmx512m, TERM -> xterm ...) 

// Just to prove it's got Scala functionality: 

scala> env.filterKeys(_.indexOf("TERM")>=0) 
res6: scala.collection.immutable.Map[String,String] = Map(TERM -> xterm, 
    TERM_PROGRAM -> iTerm.app, ITERM_PROFILE -> Default) 

Funziona bene con una java.util.map di stringa per booleano.

Problemi correlati