Java/Scala(深层)集合互操作性
你能分享一下你的观点吗?什么是最优雅和/或最有效的转换方式Java/Scala(深层)集合互操作性,java,scala,Java,Scala,你能分享一下你的观点吗?什么是最优雅和/或最有效的转换方式 java.util.HashMap[ java.lang.String, java.util.ArrayList[ java.util.ArrayList[java.lang.Double] ] ] (all of the objects are from java.util or java.lang) 到 谢谢, -A我并不是说它很优雅,但它很管用。我显式地而不是隐式地使用来自JavaConver
java.util.HashMap[
java.lang.String, java.util.ArrayList[
java.util.ArrayList[java.lang.Double]
]
]
(all of the objects are from java.util or java.lang)
到
谢谢,
-A我并不是说它很优雅,但它很管用。我显式地而不是隐式地使用来自
JavaConversions
的转换,以允许类型推断稍微有所帮助JavaConversions
是Scala 2.8中的新功能
import collection.JavaConversions._
import java.util.{ArrayList, HashMap}
import collection.mutable.Buffer
val javaMutable = new HashMap[String, ArrayList[ArrayList[Double]]]
val scalaMutable: collection.Map[String, Buffer[Buffer[Double]]] =
asMap(javaMutable).mapValues(asBuffer(_).map(asBuffer(_)))
val scalaImmutable: Map[String, List[List[Double]]] =
Map(asMap(javaMutable).mapValues(asBuffer(_).map(asBuffer(_).toList).toList).toSeq: _*)
更新:这里有一种替代方法,使用隐式将给定的转换集应用于任意嵌套结构
trait ==>>[A, B] extends (A => B) {
def apply(a: A): B
}
object ==>> {
def convert[A, B](a: A)(implicit a2b: A ==>> B): B = a
// the default identity conversion
implicit def Identity_==>>[A] = new (A ==>> A) {
def apply(a: A) = a
}
// import whichever conversions you like from here:
object Conversions {
import java.util.{ArrayList, HashMap}
import collection.mutable.Buffer
import collection.JavaConversions._
implicit def ArrayListToBuffer[T, U](implicit t2u: T ==>> U) = new (ArrayList[T] ==>> Buffer[U]) {
def apply(a: ArrayList[T]) = asBuffer(a).map(t2u)
}
implicit def HashMapToMap[K, V, VV](implicit v2vv: V ==>> VV) = new (HashMap[K, V] ==>> collection.Map[K, VV]) {
def apply(a: java.util.HashMap[K, V]) = asMap(a).mapValues(v2vv)
}
}
}
object test {
def main(args: Array[String]) {
import java.util.{ArrayList, HashMap}
import collection.mutable.Buffer
// some java collections with different nesting
val javaMutable1 = new HashMap[String, ArrayList[ArrayList[Double]]]
val javaMutable2 = new HashMap[String, ArrayList[HashMap[String, ArrayList[ArrayList[Double]]]]]
import ==>>.{convert, Conversions}
// here comes the elegant part!
import Conversions.{HashMapToMap, ArrayListToBuffer}
val scala1 = convert(javaMutable1)
val scala2 = convert(javaMutable2)
// check the types to show that the conversion worked.
scala1: collection.Map[String, Buffer[Buffer[Double]]]
scala2: collection.Map[String, Buffer[collection.Map[String, Buffer[Buffer[Double]]]]]
}
}
执行此操作的方法已从2.7更改为2.8。Retronym的方法适用于2.8。对于2.7,您应该改为使用
collections.jcl
如下所示:
object Example {
import scala.collection.jcl
// Build the example data structure
val row1 = new java.util.ArrayList[Double]()
val row2 = new java.util.ArrayList[Double]()
val mat = new java.util.ArrayList[java.util.ArrayList[Double]]()
row1.add(1.0) ; row1.add(2.0) ; row2.add(3.0) ; row2.add(4.0)
mat.add(row1) ; mat.add(row2)
val named = new java.util.HashMap[String,java.util.ArrayList[java.util.ArrayList[Double]]]
named.put("matrix",mat)
// This actually does the conversion
def asScala(thing: java.util.HashMap[String,java.util.ArrayList[java.util.ArrayList[Double]]]) = {
Map() ++ (new jcl.HashMap(thing)).map(kv => {
( kv._1 ,
(new jcl.ArrayList(kv._2)).map(al => {
(new jcl.ArrayList(al)).toArray
}).toArray
)
})
}
}
因此,总体思路是:从外到内,将Java集合封装在Scala等价物中,然后使用map将所有内容封装到下一个级别。如果要在Scala表示法之间进行转换,请在退出时进行转换(此处,末尾的.toArray
)
在这里,您可以看到示例正在运行:
scala> Example.named
res0: java.util.HashMap[String,java.util.ArrayList[java.util.ArrayList[Double]]] = {matrix=[[1.0, 2.0], [3.0, 4.0]]}
scala> val sc = Example.asScala(Example.named)
sc: scala.collection.immutable.Map[String,Array[Array[Double]]] = Map(matrix -> Array([D@1ea817f, [D@dbd794))
scala> sc("matrix")(0)
res1: Array[Double] = Array(1.0, 2.0)
scala> sc("matrix")(1)
res2: Array[Double] = Array(3.0, 4.0)
@若你们的收藏是同质的,那个么retronym的答案是好的,但当我有一个混合的收藏时,它似乎对我不起作用。例如:
valx=Map(5->Array(1,List(2,7,3),6->Map(5->List(7,8,9))
要将这样的集合转换为java,您需要依赖于运行时类型,因为x
的类型不能在编译时递归转换为java。下面是一个可以处理将混合scala集合转换为java的方法:
def convert(x:Any):Any =
{
import collection.JavaConversions._
import collection.JavaConverters._
x match
{
case x:List[_] => x.map{convert}.asJava
case x:collection.mutable.ConcurrentMap[_, _] => x.mapValues(convert).asJava
case x:collection.mutable.Map[_, _] => x.mapValues(convert).asJava
case x:collection.immutable.Map[_, _] => x.mapValues(convert).asJava
case x:collection.Map[_, _] => x.mapValues(convert).asJava
case x:collection.mutable.Set[_] => x.map(convert).asJava
case x:collection.mutable.Buffer[_] => x.map(convert).asJava
case x:Iterable[_] => x.map(convert).asJava
case x:Iterator[_] => x.map(convert).asJava
case x:Array[_] => x.map(convert).toArray
case _ => x
}
}
可以编写一个类似的方法来将java转换为scala
请注意,此方法的返回类型是
Any
,因此为了使用返回的值,您可能必须执行强制转换:val y=convert(x).asInstanceOf[java.util.Map[Int,Any]]
这不是更大的设计问题吗?这个结构的语义是什么?为什么要转换这些对象?实际上,我正在通过jackson json库从json文件读取这些数据(我尝试了sjson和lift json,但都失败了)。Jackson json没有scala api,所以我使用java api来完成这项工作。
def convert(x:Any):Any =
{
import collection.JavaConversions._
import collection.JavaConverters._
x match
{
case x:List[_] => x.map{convert}.asJava
case x:collection.mutable.ConcurrentMap[_, _] => x.mapValues(convert).asJava
case x:collection.mutable.Map[_, _] => x.mapValues(convert).asJava
case x:collection.immutable.Map[_, _] => x.mapValues(convert).asJava
case x:collection.Map[_, _] => x.mapValues(convert).asJava
case x:collection.mutable.Set[_] => x.map(convert).asJava
case x:collection.mutable.Buffer[_] => x.map(convert).asJava
case x:Iterable[_] => x.map(convert).asJava
case x:Iterator[_] => x.map(convert).asJava
case x:Array[_] => x.map(convert).toArray
case _ => x
}
}