2009-06-22 13 views
14

Una API de Java devuelve java.util.Map<java.lang.String,java.lang.Boolean>;. Me gustaría poner esto en un Map[String,Boolean]Cómo convertir de java.util.Map a un mapa de Scala

Así que imaginemos que tenemos:

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

No se puede hacer Map.empty ++ javaMap, ya que el método ++ no sabe acerca de los mapas de Java. Probé:

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

y:

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

Estos ambos fallan para compilar, a causa de los medicamentos genéricos - java.lang.String no es lo mismo que una cadena Scala.

¿Hay una buena manera de hacer esto, salvo copiar el mapa manualmente?

EDIT: Gracias, todas las buenas respuestas, he aprendido mucho de todas ellas. Sin embargo, cometí un error al publicar un problema más simple aquí que el que realmente tengo. Por lo tanto, si usted me lo permite, voy a generalizar la pregunta - ¿Qué la API devuelve realidad es

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

Y necesito mover este a Mapa [Cadena, mapa [SomeJavaEnum, String]]

Se probablemente no parezca demasiada complicación, pero agrega un nivel extra de borrado de tipo, y la única forma que encontré de mover esto a un mapa de Scala fue haciendo una copia profunda (usando algunas de las técnicas que sugeriste a continuación). Alguien alguna sugerencia? De alguna manera, resolví mi problema definiendo una conversión implícita para mis tipos exactos, por lo que al menos la fealdad está oculta en su propio rasgo, pero aún se siente un poco torpe copiando el lote.

+0

Me gusta bastante la respuesta de Conversiones que obtuve del grupo de usuarios de scala. Solo necesito verificar si funciona ... Pero ya es demasiado tarde aquí, así que volveré a publicar pronto ... – George

Respuesta

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

de comandos

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

Ninguno de estos dos trabajos, me temo. Estas son clases genéricas - Map [String, Boolean] no es lo mismo que Map [java.lang.String, java.lang.Boolean], por lo que obtienes: type incompectablemente; encontrado: java.lang.Object con scala.collection.jcl.MapWrapper [String, Boolean] \t {...} requerido: Map [String, Boolean] (usando el primer ejemplo) – George

+0

tuvo tiempo para probarlo. muestra completa provista – jitter

+0

Gracias, 'Map.empty ++ JMapWrapper [K, V] (myJavaMap)' ¡es lo que quiero! –

0

Creo que tengo una respuesta parcial ...

Si convierte el mapa de Java en un mapa scala con los tipos de Java. A continuación, puede asignar a un mapa de tipos de Scala 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]) 
} 

El defecto de este plan es que el tipo de scalaMap es Iterable [(java.lang.String, Boolean)] no es un mapa. Me siento tan cerca, ¿alguien más listo que yo puede arreglar la última declaración para que esto funcione?

6

Un Scala String es un java.lang.Stringpero a Scala Booleanno es unjava.lang.Boolean.Por lo tanto, las siguientes obras:

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 

Pero el problema sigue siendo el problema con la diferencia Boolean. Vas a tener que "doblar" el mapa de Java en el Scala uno: inténtelo de nuevo usando el 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) } 

Luego se mm un mapa Scala que contiene los contenidos del mapa Scala original más lo que era en el Java map

+0

En realidad, su respuesta se convierte en mapa mutable, mientras que el autor pidió inmutables. –

11

Al menos con Scala 2.9.2 hay una manera más fácil con las conversiones de colecciones: importe "import collection.JavaConversions._" y use "toMap".

Ejemplo:

// 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) 

Funciona bien con un java.util.map de cadena a Boole.

Cuestiones relacionadas