entre - ¿Cómo puedo convertir un mapa Java de mapas para usar en Scala?
recorrer hashmap java (4)
Estoy trabajando en un programa Scala que llama a una función desde una biblioteca Java, procesa los resultados y genera un CSV.
La función de Java en cuestión se ve así:
Map<String, Map<String, AtomicLong>> getData();
The Scala:
import scala.collection.JavaConversions._
def analysisAndCsvStuff(data: Map[String, Map[String, AtomicLong]]): Unit { ... }
El error:
type mismatch;
found:java.util.Map[java...String,java...Map[java...String,java...AtomicLong]]
required: scala...Map[String,scala...Map[String,java...AtomicLong]]
(Los nombres de ruta estaban arruinando el formateo).
Supongo que las JavaConversions pueden convertir con éxito el java externo ... Mapa, pero no el Java interior ... Mapa. Vi esta pregunta, pero no estoy seguro de cómo escribir una "conversión implícita explícita".
No estoy seguro de cómo escribir una "conversión implícita explícita"
Usando JavaConverters
por supuesto, esa frase sugiere una implícita personalizada.
Aquí está el vaivén:
scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._
scala> import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicLong
scala> val m = Map("a" -> Map("b" -> new AtomicLong(7L)))
m: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,java.util.concurrent.atomic.AtomicLong]] = Map(a -> Map(b -> 7))
scala> val j = m mapValues (_.asJava) asJava
warning: there were 1 feature warning(s); re-run with -feature for details
j: java.util.Map[String,java.util.Map[String,java.util.concurrent.atomic.AtomicLong]] = {a={b=7}}
scala> implicit class mapmap[A,B,C](val v:
| java.util.Map[A,java.util.Map[B,C]]) extends AnyVal {
| def asMapMap: Map[A,Map[B,C]] =
| v.asScala.toMap.mapValues(_.asScala.toMap)
| }
defined class mapmap
scala> j.asMapMap
res0: Map[String,Map[String,java.util.concurrent.atomic.AtomicLong]] = Map(a -> Map(b -> 7))
En primer lugar, hay 2 versiones de Maps
y otras colecciones importantes en scala, mutable e inmutable. El uso predeterminado es la versión inmutable, y puede acceder a la versión mutable a través del paquete scala.collection.mutable
.
Debido a la mutabilidad de las colecciones de Java, la conversión de las colecciones de Java a las colecciones de scala mutable es mucho más fácil que la conversión a colecciones scala inmutables. JavaConversions
no puede convertir colecciones de java en scala colecciones inmutables.
Además, JavaCollections
no puede convertir sus colecciones internas a tipos scala.
Le sugiero que convierta su Mapa de Java como una estructura de datos scala de la siguiente manera.
val javaMap:java.util.HashMap[String,java.util.Map[String,Int]] = new java.util.HashMap()
val scalaMap:Map[String,Map[String,Int]] = javaMap.toMap.map { case (k,v) => k -> v.toMap}
El método .tomap
se define en scala.collection.mutable.Map
que convierte mutable Map
immutable Map
. y JavaConversions
convierte java.util.Map
en scala inmutable Map
alternativamente puede usar la biblioteca scalaj-collection que escribí específicamente para este propósito
import com.daodecode.scalaj.collection._
analysisAndCsvStuff(getData.deepAsScala)
Eso es. Convertirá todas las colecciones java anidadas y tipos primitivos en versiones scala. También puede convertir directamente a estructuras de datos inmutables utilizando deepAsScalaImmutable
(con algunos gastos de copia, por supuesto)
Editar : la forma recomendada es usar JavaConverters
y el método .asScala
:
import scala.collection.JavaConverters._
val myScalaMap = myJavaMap.asScala.mapValues(_.asScala)
Tenga en cuenta que obtendrá mapas mutables de esto. Siempre puede usar .asScala.toMap
si quiere inmutables.
La respuesta original con JavaConversions
:
La respuesta corta es: llamar a .mapValues
en el mapa externo para convertir el mapa interno:
import scala.collection.JavaConversions._
val myScalaMap = myJavaMap.mapValues(_.toMap)
.mapValues
fuerza la conversión o el mapa externo a un Map
scala y .toMap
fuerza la conversión del mapa interno a un mapa scala ( inmutable ). La parte inmutable no es estrictamente necesaria, pero de todos modos ...
Esto es muy similar a este awser . Ejemplo corto:
scala> val a: java.util.Map[String, java.util.Map[String, String]] = new java.util.HashMap[String, java.util.Map[String, String]]
a: java.util.Map[String,java.util.Map[String,String]] = {}
scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._
scala> val myScalaMap = a.mapValues(_.toMap)
myScalaMap: scala.collection.Map[String,scala.collection.immutable.Map[String,String]] = Map()