【问题标题】:How can I convert a Java map of maps for use in Scala?如何转换 Java 地图地图以在 Scala 中使用?
【发布时间】:2013-06-07 13:37:53
【问题描述】:

我正在开发一个 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。我看到了this question,但我不确定如何编写“显式隐式转换”。

【问题讨论】:

    标签: java scala type-conversion scala-java-interop


    【解决方案1】:

    编辑recommended way 是使用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(不可变)映射。不可变部分不是绝对必要的,但无论如何......

    这与this 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()
    

    【讨论】:

    • 嘘!完美运行。感谢您快速简洁的回复!
    • @SamDaniel np :)。请参阅我的更新,尽管两个版本都完全有效。
    • 我认为是 JavaConverters 版本。我评论了人们强烈推荐使用 asScala 的链接答案。
    • @som-snytt 谢谢,我不确定。然后令人惊讶的是 JavaConversions 在 2.11 中没有被弃用。
    【解决方案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))
    

    【讨论】:

    • 谢谢!起初,Scala 的“隐式”对我来说似乎是巫术,一个 Scala n00b 和一个受过 ML 类型系统艺术训练的人。但我很确定我现在明白它是如何工作的。
    【解决方案3】:

    首先,在scala中有2个版本的Maps和其他主要的集合,可变的和不可变的。默认使用不可变版本,可以通过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 Map 转换为immutable MapJavaConversionsjava.util.Map 转换为 scala 不可变 Map

    【讨论】:

      【解决方案4】:

      您也可以使用我专门为此目的编写的scalaj-collection

      import com.daodecode.scalaj.collection._
      
      analysisAndCsvStuff(getData.deepAsScala)
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-18
        • 1970-01-01
        相关资源
        最近更新 更多