简介
今天在线上遇到一个很棘手的scala的Map集合转换为java的Map集合中类型转换异常的问题,百度上并没有找到相关解决方案。这儿特地记录一下这个问题。在叙述这个问题之前觉得有必要在记录一下常用的scala和java转换的知识。熟悉scala开发的人对scala.collection.JavaConversions._
和scala.collection.JavaConverters._
肯定不陌生,这两个工具包封装了隐式java和scala集合相互转换的API。
scala与java集合相互转换
使用JavaConversions
与JavaConverters
都可以进行转换,需要注意的是:下面演示的无论是java还是scala相关的集合对象,其泛型参数类型都是scala的基本数据类型
,这一点非常重要!
- JavaConverters完成List集合转换
import scala.collection.JavaConverters._
// 创建泛型为Int类型的scala List集合
val scalaList:List[Int]= List(1,2,3,4,5)
// 将scala List集合转java List集合
val javaList:java.util.List[Int] = scalaList.asJava
// 创建java List集合
val List = new util.ArrayList[Int]()
// 将java List集合转为scala List集合
val scalalist2 = list.asScala
- JavaConverters完成Map集合转换
import scala.collection.JavaConverters._
// 创建scala的map集合
val map: Map[String, Int] = Map("8" -> 15, "4" -> 3000)
// 将scala的map集合转为java map集合
val javaMap = map.asJava
// 创建java的Map集合
val javaMap1 = new util.HashMap[String,Int]()
// 将java的Map集合转为scala的Map
val scalaMap = javaMap1.asScala
这里特地说一下:JavaConversions转换都是隐式
的。
- JavaConversions 完成List集合转换
import scala.collection.JavaConversions._
// 创建泛型为Int类型的scala List集合
val scalaList: List[Int] = List(1, 2, 3, 4, 5)
// 将scala List集合转java List集合
val javaList =seqAsJavaList(scalaList)
// 创建java List集合
val list = new util.ArrayList[Int]()
// 将java List集合转为scala List集合
val scalalist2 = list.toList
- JavaConversions 完成Map集合转换
import scala.collection.JavaConversions._
// 创建java的Map集合
val javaMap = new util.HashMap[String,Int]()
// 将java的Map集合转为scala的Map
val scalaMap = javaMap.toMap
// 创建scala的map集合
val map: Map[String, Int] = Map("8" -> 15, "4" -> 3000)
// 将scala的map集合转换成java的map集合
val javaMap = mapAsJavaMap(map)
以上两个包下还提供了其他scala和java数据类型转换如set
集合等,具体可以参考官方文档,这里就不在介绍了。
错误定位
上面介绍java和scala集合转换的示例,这次错误主要是scala的集合泛型中Long数据类型转换java的集合中直接转换成java的Integer,而不是我们想要的java的Long类型。
项目中参数的返回值如下图所示:
可以很清晰看到返回的参数是Map[String, Long]
,而这个返回值作为了项目中的一个方法的入参参数如下图所示:
这里的Map对象是java.util.Map那个对象,所以这儿自然就想到将scala的Map[String, Long]
转换java对应的数据集合类型就好。但是编译报了类型不匹配的的错误:
现在才发现上面转换后的java的Map集合泛型类型是scala的数据类型,并不是原生的java数据类型。所以这儿将上面的集合做一次类型转换,就像下面这样:
mapAsJavaMap(prize).asInstanceOf[java.util.Map[java.lang.String,java.lang.Long]]
这么写好了大功告成,but当测试的时候,发现执行报了以下的错误:
这里报了类型转换的异常,从Map[String, Long]
到java.util.Map[java.lang.String,java.lang.Long]
转换过程应该是这样的过程:scala的Long类型转换成了java的Integer类型,然后在将这个Integer类型转成java的Long类型
。
解决
查阅百度相关博客,大多数都是scala和java集合转换的相关博客,并没有集合转换异常的收录。最后抱着试一试的态度将最开始的findMap4Prize
这个方法的返回值修改为:Map[String, java.lang.Long]
发现问题竟然解决了。原生的scala的Long类型竟然不可以直接转换成java的Long类型数据
,猜测应该是scala语言的一个bug(本人使用scala的版本号是2.11.8)。
若类似scala集合转化java集合出现的cast exception
都可以直接将scala集合的泛型类型设置为java的数据类型即可。