Uko*_* Ra 1 java performance scala
假设我有一个带有一些业务逻辑的 Java 类:
package examples;
import java.util.List;
import java.util.Map;
public class Inner {
public void consume(Map<Integer, List<Double>> map) {
map.forEach((k, v) -> {
System.out.println("Key: " + k);
v.forEach(i -> System.out.println(" item: " + i));
});
}
}
Run Code Online (Sandbox Code Playgroud)
现在我想编写一个高性能的、尽可能原生的Scala 包装器(因为这个包装器可能会被高频调用),所以:
package examples
class Wrapper(val asJava: Inner) extends AnyVal {
implicit def consume(map: Map[Int, List[Double]]): Unit = asJava.consume(map)
}
Run Code Online (Sandbox Code Playgroud)
但得到错误:
[error] found : Map[Int,List[Double]] (in scala.collection.immutable)
[error] required: Map[Integer,java.util.List[Double]] (in java.util)
[error] implicit def consume(map: Map[Int, List[Double]]): Unit = asJava.consume(map)
[error] ^
[error] one error found
Run Code Online (Sandbox Code Playgroud)
[error] found : Map[Int,List[Double]] (in scala.collection.immutable)
[error] required: Map[Integer,java.util.List[Double]] (in java.util)
[error] implicit def consume(map: Map[Int, List[Double]]): Unit = asJava.consume(map)
[error] ^
[error] one error found
Run Code Online (Sandbox Code Playgroud)
仍然有错误:
[error] found : java.util.Map[Int,List[scala.Double]]
[error] required: java.util.Map[Integer,java.util.List[java.lang.Double]]
[error] implicit def consume(map: Map[Int, List[Double]]): Unit = asJava.consume(map.asJava)
[error] ^
[error] one error found
Run Code Online (Sandbox Code Playgroud)
而且恐怕scala.jdk.CollectionConverters._会分配额外的内存,浪费很多时间
scala.jdk.CollectionConverters._在高性能场景中使用吗?更新 1:我已经扩展了答案以提供更多细节和解释。
在Scala定义中使用Integer而不是Int,而java.lang.Double不是scala.Double(这是Double在Scala 中被解释的)。
问题是Java不允许在集合中使用原语,这就是为什么它使用Integer而不是int作为类型,而Double不是double. 在Scala中Int,Double、 等的处理更为复杂。在大多数情况下,它会将它们视为原语(即,像Java的int、double等),但在与集合一起使用时会将它们装箱(和拆箱)。
但是,在与Java互操作时,需要更加明确。Scala会Integer在必要时将实例隐式转换为Int实例,反之亦然,但它不能隐式转换装箱原语的集合。
您可以在Scala 中很好地使用Java集合,而且开销为零;您根本不需要将它们转换为Scala等效项。但是,如果您将转换传递给需要Scala等效集合的代码,或者如果您想将Scala集合与遗留Java代码一起使用,您显然需要执行转换。(如果它是不明确的,一个是不一样的一个,也不是一个相同的作为该Scala的集合是不可变的,并设计用于使用有效使用功能的编程范例。)java.util.Mapscala.collection.immutable.Mapjava.util.Listscala.collection.immutable.List
如果您担心性能,则应该使用微基准测试工具包,例如ScalaMeter,它可以让您准确地衡量本地使用Java集合与转换为/从Scala集合之间的比较。
更新 2:
我已经使用Java的集合重新编写了您的第一次尝试。为了避免与Scala类型混淆,我通过在它们前面加上前缀来重命名冲突的Java类型J:
package examples
import java.lang.{Double => JDouble}
import java.util.{List => JList, Map => JMap}
import scala.language.implicitConversions
class Wrapper(val asJava: Inner) {
implicit def consume(map: JMap[Integer, JList[JDouble]]): Unit = {
asJava.consume(map)
}
}
Run Code Online (Sandbox Code Playgroud)
这使用 JavaMap和List集合,以及装箱原语。它可以编译,但它绝对不会给您带来任何好处( 的签名与Wrapper.consume完全相同Inner.consume)。但是,它确实说明了如何在Scala中原位使用Java集合。
如果你想使用Scala集合,并转换为Java等价物,我认为这是你第二次尝试的意图,那么它看起来像这样:
package examples
import java.lang.{Double => JDouble}
import scala.jdk.CollectionConverters._
import scala.language.implicitConversions
class Wrapper(val asJava: Inner) {
implicit def consume(map: Map[Int, List[Double]]): Unit = {
val jmap = map.asInstanceOf[Map[Integer, List[JDouble]]]
asJava.consume(jmap.map(p => p._1 -> p._2.asJava).asJava)
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们首先必须将集合转换为使用装箱类型(定义在引擎盖下是等效的),这样没有开销。
然后我们必须将Scala数据结构转换为等效的Java数据结构。如果只是将Scala数据结构包装在Java接口中,这样做显然会产生开销。
更新 3
我还应该指出,制作这种Wrapper.consume方法implicit是一个奇怪的选择。我认为您可能打算创建 class implicit,以便(在第二次尝试中)您可以使用实例隐式使用Scala数据结构Inner。(实际上,Inner由Wrapper. 中提供的函数装饰。)Inner实例将被隐式转换为Wrapper实例,没有开销(这Wrapper在大多数情况下甚至不会创建实例,因为有extending AnyVal子句):
import java.lang.{Double => JDouble}
import scala.jdk.CollectionConverters._
import scala.language.implicitConversions
package object examples {
implicit class Wrapper(val asJava: Inner) extends AnyVal {
def consume(map: Map[Int, List[Double]]): Unit = {
val jmap = map.asInstanceOf[Map[Integer, List[JDouble]]]
asJava.consume(jmap.map(p => p._1 -> p._2.asJava).asJava)
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,Wrapper现在需要在package object. (这是因为隐式类只能在object某种类型的an中定义,必须将其引入范围,而 apackage object通常是实现此目的的最方便的方法。)
| 归档时间: |
|
| 查看次数: |
379 次 |
| 最近记录: |