当前位置: 首页 > 面试题库 >

Java <-> Scala互操作:透明列表和地图转换

方璞
2023-03-14
问题内容

我正在学习Scala,并且有一个Java项目可以迁移到Scala。我想通过逐个重写类并检查新类没有破坏项目来迁移它。

该Java项目使用java.util.Listjava.util.Map。在新的Scala类中,我想使用Scala
ListMap拥有漂亮的Scala代码。

问题在于新类(在Scala中添加了新类)无法与现有Java代码无缝集成:Java需要java.util.List,Scala需要自己的scala.List

这是问题的简化示例。有 MainLogicDao类 。他们在一行中互相调用: Main- > Logic-> Dao

public class Main {
    public void a() {
        List<Integer> res = new Logic().calculate(Arrays.asList(1, 2, 3, 4, 5));
    }
}

public class Logic {
    public List<Integer> calculate(List<Integer> ints) {
        List<Integer> together = new Dao().getSomeInts();
        together.addAll(ints);
        return together;
    }
}

public class Dao {
    public List<Integer> getSomeInts() {
        return Arrays.asList(1, 2, 3);
    }
}

在我的情况下, MainDao 类是框架类(我不需要迁移它们)。Class Logic 是业务逻辑,它将从Scala的出色功能中受益匪浅。

我需要在Scala中重写 Logic 类,同时保持 MainDao 类的完整性。最好的重写看起来像(不起作用):

class Logic2 {
  def calculate(ints: List[Integer]) : List[Integer] = {
      val together: List[Integer] = new Dao().getSomeInts()
      together ++ ints
  }
}

理想的行为: Logic2 中的列表是本机Scala列表。所有进/出java.util.Lists都自动装箱/拆箱。但这是行不通的。

相反,这确实可行(由于scala-javautils(GitHub)):

import org.scala_tools.javautils.Implicits._

class Logic3 {
  def calculate(ints: java.util.List[Integer]) : java.util.List[Integer] = {
      val together: List[Integer] = new Dao().getSomeInts().toScala
      (together ++ ints.toScala).toJava
  }
}

但是看起来很丑。

如何在Java <-> Scala之间实现列表和地图的透明魔术转换(无需执行toScala / toJava)?

如果不可能,那么使用java.util.List和朋友迁移Java-> Scala代码的最佳实践是什么?


问题答案:

相信我; 您不 希望
来回透明转换。这正是这些scala.collection.jcl.Conversions功能试图执行的操作。在实践中,这会引起很多头痛。

这种方法的问题根源在于,Scala会根据需要自动注入隐式转换,以使方法调用起作用。这可能会带来一些非常不幸的后果。例如:

import scala.collection.jcl.Conversions._

// adds a key/value pair and returns the new map (not!)
def process(map: Map[String, Int]) = {
  map.put("one", 1)
  map
}

对于Scala集合框架的新手,甚至不可变集合的概念,此代码不会完全不合时宜。不幸的是,这是完全错误的。此函数的结果是
一张图。对的调用会put触发对的隐式转换java.util.Map<String, Int>,该转换很乐意接受新值并被立即丢弃。原始文件map未经修改(实际上是不可变的)。

豪尔赫·奥尔蒂斯(Jorge Ortiz)最好地指出,您仅应出于以下两个目的之一来定义隐式转换:

  • 添加成员(方法,字段等)。这些转换应为 范围内其他任何内容均 无关 的新类型。
  • “修复”破碎的类层次结构。因此,如果您有某些类型,A并且B这些类型无关。您可以定义一个转换,A => B当且 当您希望拥有A <: B<:表示“子类型”)时。

由于java.util.Map显然不是与我们层次结构中的任何事物都无关的新类型,因此我们不能属于第一个附带条件。因此,我们唯一的希望是我们的转换Map[A, B] => java.util.Map[A, B]有资格获得第二个。但是,Scala
Map继承自绝对没有任何意义java.util.Map。它们实际上是完全正交的接口/特征。如上所述,尝试忽略这些准则几乎总是会导致奇怪和意外的行为。

事实是javautils
asScalaasJava方法旨在解决这个确切的问题。从中的javautils中有一个隐式转换(实际上有许多转换)Map[A, B] => RichMap[A, B]
RichMap是javautils定义的全新类型,因此它的唯一目的是向中添加成员Map。特别是,它添加了asJava方法,该方法返回一个包装器映射,该包装器实现java.util.Map并委托给您的原始Map实例。这使过程更加明确,并且出错的可能性也大大降低。

换句话说,使用asScalaasJava
最佳做法。在生产应用程序中独立走过这两条路之后,我可以直接告诉您javautils方法更安全,更容易使用。不要仅仅为了节省自己的8个字符而试图规避其保护!



 类似资料:
  • 在这个问题中,我必须调用一个第三方Java库,该库期望,其结果来自Scala例程返回。 我会将Scala-Future封装到一个新的Java-Future中,但是没有办法实现Java-Future方法< code > def cancel(mayinterruptirunning:Boolean):Boolean ,因为它会中断封装的Scala-Future(否则请告诉我)。 我该如何解决这个问题

  • 我有一个java map:

  • 问题内容: 我想转换一个从Java中8是这样的: 因为我有一个字符串列表,所以我想创建一个Map,键是列表的字符串,值是Integer(零)。 我的目标是计算字符串列表的元素(在我的代码中稍后)。 我知道以“旧”方式进行转换很容易; 但我想知道是否还有Java 8解决方案。 问题答案: 如前所述,参数必须是函数,因此必须更改为(可以使用任何其他参数名称代替)。 但是请注意,如果中存在重复项,此操作

  • 基本上我的问题分为两部分。 > 我想知道将要操纵像素并将特定颜色转换为透明像素的首选/快速方法。 我想知道我是否能够使用这个“BuffereImage”,而不必将其保存为支持“png”等透明度的文件格式 我找到了一种设置单个像素的方法 这儿呢 正如它所提到的,这是一种“缓慢的方法” 我发现这个线程Java:用透明像素填充BufferedImage 哪一条评论提到了“int[]”和操纵像素。 本质上

  • 问题内容: 我已经读过Clojure vs. Scala的各种论述,而我意识到两者都有自己的位置。关于将Clojure和Scala进行比较时,有一些注意事项尚未得到完整的解释: 1.)两种语言中哪一种通常 更快 ?我意识到这从一种语言功能到另一种语言功能都会有所不同,但是对性能进行总体评估会有所帮助。例如:我知道Python字典的速度非常快。但作为一个整体,它是一个 多 比Java慢语。我不想和C

  • 问题内容: 我需要在Java中实现一个返回Scala的方法。 但是我遇到这个错误: 到目前为止,这是我的代码: 但似乎没有提供将其转换为的可能性。 问题答案: 我需要JavaConverters来解决这个问题。