5

我正在开发一个 Scala 程序,该程序从 Java 库中调用一个函数,处理结果,然后输出一个 CSV。

有问题的 Java 函数如下所示:

    Map<String, Map<String, AtomicLong>> getData();

斯卡拉:

    import scala.collection.JavaConversions._
    def analysisAndCsvStuff(data: Map[String, Map[String, AtomicLong]]): Unit { ... }

错误:

    type mismatch;
    found:java.util.Map[java...String,java...Map[java...String,java...AtomicLong]]
    required: scala...Map[String,scala...Map[String,java...AtomicLong]]

(路径名破坏了格式。)

我猜 JavaConversions 可以成功转换外部 java...Map 但不能转换内部 java...Map。我看到了这个问题,但我不确定如何编写“显式隐式转换”。

4

4 回答 4

9

编辑推荐的方法是使用JavaConverters.asScala方法:

import scala.collection.JavaConverters._
val myScalaMap = myJavaMap.asScala.mapValues(_.asScala)

请注意,您将从中获得可变映射。.asScala.toMap如果你想要不可变的,你可以随时使用。


原来的答案是JavaConversions

简短的回答是:调用.mapValues外部地图来转换内部地图:

import scala.collection.JavaConversions._
val myScalaMap = myJavaMap.mapValues(_.toMap)

.mapValues将转换或外部映射强制转换为 scala ,Map并将.toMap内部映射强制转换为 scala(不可变)映射。不可变部分不是绝对必要的,但无论如何......

这与这个 anwser非常相似。简短的例子:

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()
于 2013-06-11T16:12:00.103 回答
2

我不确定如何编写“显式隐式转换”

当然,使用JavaConverters这个短语暗示了一个自定义的隐式。

这是来回的:

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))
于 2013-06-12T00:13:52.730 回答
0

首先,Mapsscala 中有 2 个版本的和其他主要的集合,可变的和不可变的。默认使用不可变版本,可以通过 scala.collection.mutable包获取可变版本。

由于 java Collections 的可变性,将 java Collections 转换为 scala mutable Collections 比转换为 scala immutable Collections 容易得多。JavaConversions无法将 java 集合转换为 scala 不可变集合。

此外,JavaCollections无法将您的内部集合转换为 scala 类型。

我建议您将您的 java Map 转换为 scala 数据结构,如下所示。

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}

.tomap方法定义在scala.collection.mutable.Map其中转换mutable Mapimmutable Map. 并JavaConversions转换java.util.Map为 scala 不可变Map

于 2013-06-11T16:51:24.137 回答
0

或者,您可以使用我专门为此目的编写的scalaj-collection库

import com.daodecode.scalaj.collection._

analysisAndCsvStuff(getData.deepAsScala)

而已。它将所有嵌套的 java 集合和原始类型转换为 scala 版本。您还可以使用deepAsScalaImmutable(当然有一些复制开销)直接转换为不可变数据结构

于 2016-01-29T00:47:53.393 回答