17

我正在对来自 ScalaTest 的 java 代码进行单元测试,并希望在它声明的同一语句中填充 java.util.HashMap。在 Scala 中可以做到这一点吗?

4

5 回答 5

33

有很多不同的方法可以实现这一点,到目前为止,只有其中一些出现在答案中。

方法一:既然java.util.HashMap有构造函数HashMap(Map<? extends K,? extends V> m),你可以给它传递一个有效的Java Map。您可以使用 Scala 的帮助轻松地做到这一点JavaConversions

scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._

scala> val myMap = Map(1->"Hi",2->"Bye")
myMap: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,Hi), (2,Bye))

scala> val jmap = new java.util.HashMap[Int,String](myMap)  // Need explicit types
jmap: java.util.HashMap[Int,String] = {1=Hi, 2=Bye}

这里的缺点是您必须已经有一个 Scala 映射(如果您只是要创建一个 Java 映射,可能会有点浪费),并且您必须指定类型。但它紧凑且无痛。

方法二:或者,您可以创建一个新的代码块作为声明语句,因此您甚至不需要JavaConversions可用:

scala> val jmap2 = {              
     |   val x = new java.util.HashMap[Int,String]  
     |   for ((k,v) <- List(1->"Howdy",2->"partner")) x.put(k,v)
     |   x
     | }
jmap2: java.util.HashMap[Int,String] = {1=Howdy, 2=partner}

稍微不那么紧凑,但完全通用,并且尽可能高效(或低效)。

方法三:另外,你可以创建一个 HashMap 的匿名子类,只要有一个子类是可以的(即.getClass不会返回java.util.HashMap),并使用初始化器来设置你的值:

scala> val jmap3 = new java.util.HashMap[Int,String] { 
     |   put(1,"Yo"); put(2,"bro")
     | }
jmap3: java.util.HashMap[Int,String] = {1=Yo, 2=bro}

scala> jmap3.getClass.getName
res0: java.lang.String = $anon$1

scala> jmap3.getClass.getSuperclass.getName
res1: java.lang.String = java.util.HashMap

当然,缺点是它是HashMap而不是的子类HashMap,但它比从代码块分配的版本更紧凑,因为您不需要将新映射分配给 val。

方法四:最后​​,当然,你可以创建一个方法来做你想做的事,然后调用它:

scala> def newJHM[A,B](kv: Iterable[(A,B)]) = {
     |   val jhm = new java.util.HashMap[A,B]  
     |   kv.foreach(i => jhm.put(i._1,i._2))   
     |   jhm                                   
     | }                                       
newJHM: [A,B](kv: Iterable[(A, B)])java.util.HashMap[A,B]

scala> val jmap4 = newJHM(Seq(1->"Bye",2->"Now"))  // Type inference now works
jmap4: java.util.HashMap[Int,java.lang.String] = {1=Bye, 2=Now}

这几乎没有其他的紧凑,并且无需您指定它们即可获得正确的类型,因此如果您不止一次这样做,它可能是一个有吸引力的选择。

PS 只是为了好玩,我已经展示了将一些键值对放入映射的各种方法,但它们并不特定于给定的方法(除了需要映射的#1)。根据您的喜好混合搭配。

于 2010-10-02T05:24:18.627 回答
12

您可以将映射作为匿名类进行,并将初始化作为对象实例初始化的一部分进行。

import java.util.HashMap
val jhm = new HashMap[String, Int](){
   put(key1, value1)
   put(key2, value2)
}

这实际上在 Java 中同样有效(除了需要双括号 {{}}),但在 Scala 中更为惯用。

于 2010-10-02T00:36:25.513 回答
3

基于 Randall 的回答,您可以JavaConversions提供一些帮助。

import collection.JavaConversions.asMap
import java.util.HashMap
val jhm = new HashMap[Int,String](Map(1->"one", 2->"two"))
于 2010-10-02T00:21:42.747 回答
1

当然,您可以使用所有的方法和构造函数java.util.HashMap,但是除非您有另一个方法和构造函数来提供初始值,否则这并不能提供初始化映射的方法。您可能会得到的最接近的是:

import java.util.HashMap
val jhm = new HashMap[String, Int]
«code to add key-value pairs to jhm»
于 2010-10-01T23:09:17.077 回答
0

为了使某些东西可重用,可以为初始化语法创建一个新的“Map”子类型。

它可以像这样工作(我忽略了泛型,因为我不经常使用它们,我可能会出错):

HashMap hm=new HashMap(
    new InitMap(
        new String[]{"one", "two", "three"},
        new int[]   {  1  ,   2  ,    3   };
    )
);

InitMap 类将涉及更多代码,但它是可重用且相当直接的(我真的很喜欢这种东西的数组初始化语法)。

想想看,InitMap 类不会太难。您可能想弄清楚调用了哪些方法并实现了这些方法。它可能只会调用 KeySet 和 EntrySet 方法。

当然,以这种速度,您可以简单地创建一个辅助方法,该方法采用两个数组并返回一个 HashMap 或扩展 HashMap 并添加一个新的构造函数......

于 2010-10-02T01:19:48.223 回答