Scala 转换器将 Java 个集合转换为 Wrapper 对象

Scala converters convert Java collections to Wrapper objects

我有一个 scala 函数,它 returns 一个 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 集合

JavaConverters 转换容器 to/from java "in place",而不复制数据。也就是说,如果您有一个 scala Map,并将其转换为 java,它不会创建一个全新的容器,也不会将所有数据复制到其中。相反,它只是 returns 一个包装器 class,它实现了 java 的 Map 接口,但由原始数据而不是副本支持。

这是一件好事,因为它节省了内存和时间。

接口的全部思想是用户不应该关心它背后的特定实现。 "Coding to interface" 就是这个主意。发现自己关心实际实现 classes 通常(不总是,但经常)是糟糕设计的味道。

如果您必须将数据复制到容器中,那是特定 class 的一个实例,您必须明确地执行此操作:

val javaMap = new HashMap[String, Set[String]](wrappedMap)

更好的是,首先考虑不使用 java 序列化。它缓慢、有故障、乏味、危险……并迫使你像这样跳过数百万个奇怪的圈套。现在有很多更好的选择。