14

Java API 返回一个java.util.Map<java.lang.String,java.lang.Boolean>;。我想把它放到一个Map[String,Boolean]

所以想象我们有:

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

你不能这样做Map.empty ++ javaMap,因为 ++ 方法不知道 Java 映射。我试过了:

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

和:

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

由于泛型,这些都无法编译 -java.lang.String与 scala String 不同。

除了手动复制地图之外,有没有一种好的方法可以做到这一点?

编辑:谢谢,所有好的答案,我从他们所有人那里学到了很多。但是,我在这里发布了一个比我实际遇到的问题更简单的问题,这是一个错误。所以,如果你允许我,我会概括这个问题 - API 实际返回的是

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

我需要把它移到 Map[String, Map[SomeJavaEnum,String]]

它可能看起来不太复杂,但它增加了额外的类型擦除级别,我发现将它移动到 Scala 映射的唯一方法是深度复制它(使用您在下面建议的一些技术) . 任何人有任何提示?我通过为我的确切类型定义一个隐式转换来解决我的问题,所以至少丑陋隐藏在它自己的特征中,但仍然感觉有点笨拙的深度复制很多。

4

4 回答 4

12

至少对于 Scala 2.9.2,集合转换有一种更简单的方法:导入“import collection.JavaConversions._”并使用“toMap”。

例子:

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

它适用于 String 到 Boolean 的 java.util.map。

于 2012-08-31T02:14:39.767 回答
6

Scala是Stringajava.lang.String ScalaBoolean 不是java.lang.Boolean. 因此,以下工作:

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

但是您的问题仍然是Boolean差异的问题。您必须将 Java 映射“折叠”到 scala 中:再次尝试使用 ScalaBoolean类型:

val sm: MMap[String, Boolean] = collection.mutable.Map.empty + ("WORLD" -> false)
val mm = (sm /: jm) { (s, t2) => s + (t2._1 -> t2._2.booleanValue) }

然后mm是一个包含原始 scala 映射的内容以及 Java 映射中的内容的 scala 映射

于 2009-06-22T17:52:36.310 回答
2

使用JavaMap.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.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() {}
}

命令行

javac test\test.java
scalac useJavaMap.scala
scala useJavaMap
> Map(Test -> false)
于 2009-06-22T16:22:50.630 回答
0

我想我有一个部分答案...

如果将 java 映射转换为具有 java 类型的 scala 映射。然后,您可以将其映射到 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])
}

这个计划的缺陷是类型scalaMap是 Iterable[(java.lang.String, Boolean)] 而不是映射。我感觉如此接近,比我更聪明的人能解决最后一个语句来完成这项工作吗?!

于 2009-06-22T17:40:56.373 回答