[AFAIU,CollectionConverters
是包装器,只是将对底层集合的调用委派给用户,因此代价应该是单个对象分配,然后是单个方法调用间接,例如,CollectionConverters
状态
内部,这些转换通过设置“包装器”对象来完成将所有操作转发到基础集合对象。所以在Java和Scala之间进行转换时,集合从不复制。
分析Conversion Between Java and Scala Collections实际上我们看到它只是将调用委派给SetWrapper
集合
SetWrapper
但是,请考虑以下jmh基准
underlying
class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] with Serializable { self =>
...
def size = underlying.size
...
}
给出的位置>
import org.openjdk.jmh.annotations._ import scala.jdk.CollectionConverters._ import java.{util => ju} @State(Scope.Benchmark) @BenchmarkMode(Array(Mode.Throughput)) class So31830028 { val size = 1000000 val scalaSet: Set[Int] = (1 to size).toSet val javaSet: ju.Set[Int] = (1 to size).toSet.asJava @Benchmark def scala = scalaSet.size @Benchmark def scalaAsJava = scalaSet.asJava.size @Benchmark def java = javaSet.size @Benchmark def javaAsScala = javaSet.asScala.size }
如果
sbt "jmh:run -i 10 -wi 5 -f 2 -t 1 bench.So31830028"
是简单的包装器,为什么似乎会显着降低性能?
这个问题的灵感是由[info] Benchmark Mode Cnt Score Error Units
[info] So31830028.java thrpt 20 356515729.840 ± 64691657.672 ops/s
[info] So31830028.javaAsScala thrpt 20 270053471.338 ± 36854051.611 ops/s
[info] So31830028.scala thrpt 20 448415156.726 ± 53674976.259 ops/s
[info] So31830028.scalaAsJava thrpt 20 211808793.234 ± 57898858.737 ops/s
[AFAIU,CollectionConverters是包装器,只是将对底层集合的调用委托给包装器,因此代价应该是单个对象分配,然后是单个方法调用间接,例如,...
在2.12中,CollectionConverters
为Cost of implicit conversion from java to scala collections;对于2.13,它是对scalaSet.size
的简单字段访问器调用,应该很容易内联,因此