Scala转换器将Java集合转换为包装对象

5
我有一个Scala函数,它返回一个util.Map[String], util.Set[String]
def getAcls(): Map[String, Set[String]] = {
((for (groupRole: GroupRoleAccess <- groupRoleAccess;
     user <- groupService.getGroup(groupRole.groupId).getUsers;
     permissions = roleService.getRole(groupRole.roleId)  .getPermissions)
  yield user.getUserId -> permissions).groupBy(_._1).map { case (k,v) => (k, v.flatMap(_._2).asJava)})
}

我只需在一组这些对象上调用此方法,即可获得一个util.Set [util.Map [String],util.Set [String]]

var unevaluatedacls = for (aclTemplate <- aclTemplates)
  yield aclTemplate.getAcls

当我检查unevaluatedacls时,我发现它是HashSet类型。但它的元素是Wrappers$MapWrapper类型而不是util.Map类型。因此,我无法将此对象持久化。我无法理解这种行为。当我尝试...
var unevaluatedacls = (for (aclTemplate <- aclTemplates)
  yield aclTemplate.getAcls).asJava

unevaluatedacls 也被更改为 Wrapper$SetWrapper。这是因为我在尝试将不可变的 Scala 集合转换为 Java 集合吗?我知道只有可变的 Scala 集合才能使用 JavaConverters 转换为相应的 Java 集合。

1个回答

7
JavaConverters 可以在不复制数据的情况下将容器转换成/从Java中。也就是说,如果您有一个Scala Map 并将其转换为Java,则不会创建一个全新的容器并将所有数据复制到其中。相反,它只返回一个包装类,该类实现了Java的Map接口,但由原始数据支持而不是副本。
这是一件好事,因为它节省了内存和时间。
整个接口的想法是用户不应关心其背后的具体实现。"编码接口"是这个想法。发现自己关注实际实现类通常(不总是,但经常)是糟糕设计的迹象。
如果您必须将数据复制到特定类的容器中,您必须明确执行:
val javaMap = new HashMap[String, Set[String]](wrappedMap)

更好的做法是,首先不要使用Java序列化。它很慢、有缺陷、繁琐、危险...并且迫使你跳过许多奇怪的障碍。现在有很多更好的替代方案。

但基本上,其中一些替代方案也需要Serializable接口(比如说memcached)。 - dk14
@dk14 我在谈论替代Java序列化的方案,比如Thrift、Protobufs、Avro、Cryo、JSON等。它们不需要Serializable接口。 Memcached与此毫无关系。 - Dima
我的意思是,如果没有找到适当的转码器,像spy-memcached(SerializingTranscoder)这样的框架会回退到Java序列化。一些基于反射的转码器也需要“Serializable”。我相信(不确定)scala-pickling在宏无法找到适当的“Decoder”(在编译时)时会要求“Serializable”(在运行时)。 - dk14
@dk,是的,有一些库需要实现 Serializable 接口,但也有(很多)其他可选的库不要求。这正是我所说的。 :) - Dima
这也是我的观点。我既不喜欢反射,也不喜欢Java序列化。像circe(用于json)或scodec(用于字节码,如果手动管理向后兼容性)这样的东西对我来说更好,但这不是一个完美的世界,所以有时即使使用第三方解决方案,您仍然必须处理旧的错误问题,这就是我想说的 :) 我已经+1了答案。 - dk14

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接