Java Scala枚举映射实现
Java有一个特殊的Java Scala枚举映射实现,java,scala,Java,Scala,Java有一个特殊的Map实现,专为键属于enum类型的情况而设计(请参见类声明EnumMap)。例如,java.util.HashMap的主要优势在于内存和性能效率,因为它提前知道键的数量,因为它们在枚举中声明,所以内存紧凑且速度更快,因为不需要扩展内部表和解决哈希冲突 我想知道,除了Scala的枚举和immutable.Map接口之外,这个Java实现是否有现成的Scala实现。也许有任何外部lib实现,或者有任何方法可以创建自己的实现,并具有相近的内存和性能结果 非常感谢您提前提供的帮助
Map
实现,专为键属于enum
类型的情况而设计(请参见类声明EnumMap
)。例如,java.util.HashMap
的主要优势在于内存和性能效率,因为它提前知道键的数量,因为它们在枚举中声明,所以内存紧凑且速度更快,因为不需要扩展内部表和解决哈希冲突
我想知道,除了Scala的枚举
和immutable.Map
接口之外,这个Java实现是否有现成的Scala实现。也许有任何外部lib实现,或者有任何方法可以创建自己的实现,并具有相近的内存和性能结果
非常感谢您提前提供的帮助 Enumeratum的公开发行版提供了一个信息丰富的基准
[info] MapComparisons.enumeratumScalaMapGet avgt 30 9.830 ± 0.207 ns/op
[info] MapComparisons.jEnumEnumMapGet avgt 30 4.745 ± 0.685 ns/op
[info] MapComparisons.jEnumScalaMapGet avgt 30 12.204 ± 0.186 ns/op
劳埃德梅塔在哪里
所以目前的情况是Java EnumMap和EnumSet是
大约比普通的Scala集合和带有枚举数的映射快2倍,但是
由于我们仍在10纳秒以下的范围内,因此
说这里的性能不会成为瓶颈,除非是在super edge中
案例
我尝试复制lloydmeta的基准测试,并使用Scala 2.13、enumeratum 1.5.15获得以下结果
sbt "jmh:run -i 10 -wi 10 -f 2 -t 1 -prof gc bench.So60374058"
平均时间,时间/op
enumeratumScalaMapGet avgt 20 8.284 ± 0.071 ns/op
jEnumEnumMapGet avgt 20 2.883 ± 0.023 ns/op
jEnumScalaMapGet avgt 20 7.361 ± 0.273 ns/op
vanillaScalaMapGet avgt 20 6.650 ± 0.323 ns/op
内存分配率
enumeratumScalaMapGet:·gc.alloc.rate avgt 20 1753.262 ± 14.548 MB/sec
jEnumEnumMapGet:·gc.alloc.rate avgt 20 ≈ 10⁻⁴ MB/sec
jEnumScalaMapGet:·gc.alloc.rate avgt 20 1976.491 ± 70.259 MB/sec
vanillaScalaMapGet:·gc.alloc.rate avgt 20 2190.644 ± 105.208 MB/sec
我们注意到,自2017年以来,jEnumScalaMapGet
似乎已经赶上了enumeratumScalaMapGet
以及JenumumNummapGet
的琐碎内存分配
基准资料来源:
public enum JAgeGroup {
Baby,
Toddler,
Teenager,
Adult,
Senior
}
及
@MarioGalic oh-wow上的信息基准,非常感谢您为我指出这一点。请用你提供的链接回答这个问题,这样我就可以投票并接受它了!谢谢。Scala还为小型不可变映射(最多包含4个元素)提供了特殊的实现,因此这些实现已经相当有效:@StephaneBersier谢谢您的评论。请原谅,也许我遗漏了什么,但正如名字所示,
EmptyMap
只是空映射的特殊实现。也许您想指向另一个实现,而不是那个实现?@IvanKurchenko如果您一直阅读EmptyMap
的定义,您将看到Map1
、Map2
、Map3
和Map4
的定义。
import java.util
import java.util.concurrent.TimeUnit
import example.JAgeGroup
import org.openjdk.jmh.annotations._
import org.openjdk.jmh.infra.Blackhole
import enumeratum._
object AgeGroupVanilla extends Enumeration {
type AgeGroupVanilla = Value
val Baby, Toddler, Teenager, Adult, Senior = Value
}
sealed trait AgeGroup extends EnumEntry
case object AgeGroup extends Enum[AgeGroup] {
val values = findValues
case object Baby extends AgeGroup
case object Toddler extends AgeGroup
case object Teenager extends AgeGroup
case object Adult extends AgeGroup
case object Senior extends AgeGroup
}
@State(Scope.Thread)
@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.NANOSECONDS)
class So60374058 {
private val jEnumEnumMap = {
val m: util.EnumMap[JAgeGroup, String] = new util.EnumMap(classOf[JAgeGroup])
JAgeGroup.values().foreach(e => m.put(e, e.name()))
m
}
private val jEnumScalaMap = Map(JAgeGroup.values().map(e => e -> e.name()): _*)
private val ageGroupScalaMap = Map(AgeGroup.values.map(e => e -> e.entryName): _*)
private val vanillaScalaMap = AgeGroupVanilla.values.map(e => e -> e.toString).toMap
private def randomFrom[A](seq: Seq[A]): A = {
seq(scala.util.Random.nextInt(seq.size))
}
private var jEnum: JAgeGroup = _
private var ageGroupEnum: AgeGroup = _
private var vanillaEnum: AgeGroupVanilla.AgeGroupVanilla = _
@Setup(Level.Trial)
def setup(): Unit = {
jEnum = randomFrom(JAgeGroup.values())
ageGroupEnum = randomFrom(AgeGroup.values)
vanillaEnum = randomFrom(AgeGroupVanilla.values.toSeq)
}
@Benchmark
def jEnumEnumMapGet(bh: Blackhole): Unit = bh.consume {
jEnumEnumMap.get(jEnum)
}
@Benchmark
def jEnumScalaMapGet(bh: Blackhole): Unit = bh.consume {
jEnumScalaMap.get(jEnum)
}
@Benchmark
def enumeratumScalaMapGet(bh: Blackhole): Unit = bh.consume {
ageGroupScalaMap.get(ageGroupEnum)
}
@Benchmark
def vanillaScalaMapGet(bh: Blackhole): Unit = bh.consume {
vanillaScalaMap.get(vanillaEnum)
}
}