recorrer entre ejemplo diferencia colecciones java scala type-conversion scala-java-interop

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