以下の話
JDK 25時点では java.lang.StableValue ですが、26以降で名前も機能もある程度変わるらしいです。
いずれにせよまだpreview APIなので、一般人が使うものではありませんが。
最新の26のEAでもまだLazyConstantは試せなかったので、25でのStableValueでJMHでベンチマークとりました。
すごく大雑把にいうと、目的としてはほぼScalaのlazy valに相当するような特別なclassをJavaに入れよう、という理解でいいと思います。
Java言語自体の文法拡張ではなく、あくまでclassとして入るけれど、
そのclassをJVMが特別扱いすることによって*1、特定のパターンでConstant foldingが有効になってすごくパフォーマンスが良い、
という雰囲気だと思います。
最初の初期化時の速度と、初期化済みの値に繰り返しアクセスした場合の速度と、主に2通りの観点があり得ますが、後者を計測するようなコードを書きました。
先にベンチーマーク結果が以下
[info] Benchmark Mode Cnt Score Error Units [info] Main.test1 thrpt 5 1754279333.496 ± 122744390.832 ops/s [info] Main.test2 thrpt 5 16656.956 ± 777.404 ops/s [info] Main.test3 thrpt 5 14790.373 ± 1996.905 ops/s
- test1の明らかに大きい数字がStableValueで、おそらくConstant foldingが有効になるようなコードを書いたもの
- test2がScalaのlazy val
- test3がStableValueを別の使い方したもの
です。つまり
1754279333.496 / 16656.956 = 105318倍速いです。わーい
しかし 「StableValueを別の使い方したもの」に関しては、lazy valと変わらないか、むしろ若干遅いです。 これは、Constant foldingされるようなstaticなfield相当ではないとダメなのかなんなのか・・・詳細な条件がよくわかりませんでした。 そもそも、今の時点で詳細な条件を出したところで、まだpreviewなAPIなので、今後変わる可能性もありますし。
以下に、ベンチマークのコードと、もう少し詳細なログを貼っておきます。
$ java --version openjdk 25.0.1 2025-10-21 LTS OpenJDK Runtime Environment Corretto-25.0.1.8.1 (build 25.0.1+8-LTS) OpenJDK 64-Bit Server VM Corretto-25.0.1.8.1 (build 25.0.1+8-LTS, mixed mode, sharing)
sbtのshellで以下を実行
Jmh/run -i 5 -wi 5 -f1 -t1
build.sbt
enablePlugins(JmhPlugin)
scalaVersion := "3.7.3"
project/plugins.sbt
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.8")
src/main/scala/Main.scala
package example import org.openjdk.jmh.annotations.Benchmark import java.util.function.Supplier object A1 { private val x1: Supplier[String] = StableValue.supplier(() => "x1") private val x2: Supplier[String] = StableValue.supplier(() => "x2") private val x3: Supplier[String] = StableValue.supplier(() => "x3") def value: String = x1.get + x2.get + x3.get } object A2 { private lazy val x1: String = "x1" private lazy val x2: String = "x2" private lazy val x3: String = "x3" def value: String = x1 + x2 + x3 } final class A3 { private val x1: Supplier[String] = StableValue.supplier(() => "x1") private val x2: Supplier[String] = StableValue.supplier(() => "x2") private val x3: Supplier[String] = StableValue.supplier(() => "x3") def value: String = x1.get + x2.get + x3.get } object A3 { val instance = new A3 def value: String = instance.value } class Main { @Benchmark def test1(): Int = { var s: Int = 0 var i: Int = 0 while(i < 1000) { s += A1.value.length i += 1 } s } @Benchmark def test2(): Int = { var s: Int = 0 var i: Int = 0 while(i < 1000) { s += A2.value.length i += 1 } s } @Benchmark def test3(): Int = { var s: Int = 0 var i: Int = 0 while(i < 1000) { s += A3.value.length i += 1 } s } }
# Warmup Iteration 1: 1743539488.716 ops/s # Warmup Iteration 2: 1709617887.693 ops/s # Warmup Iteration 3: 1757739240.491 ops/s # Warmup Iteration 4: 1775353507.676 ops/s # Warmup Iteration 5: 1779145061.840 ops/s Iteration 1: 1698628448.162 ops/s Iteration 2: 1757745279.793 ops/s Iteration 3: 1771000427.312 ops/s Iteration 4: 1776855341.000 ops/s Iteration 5: 1767167171.212 ops/s Result "example.Main.test1": 1754279333.496 ±(99.9%) 122744390.832 ops/s [Average] (min, avg, max) = (1698628448.162, 1754279333.496, 1776855341.000), stdev = 31876328.507 CI (99.9%): [1631534942.664, 1877023724.327] (assumes normal distribution)
# Warmup Iteration 1: 16614.712 ops/s # Warmup Iteration 2: 16421.645 ops/s # Warmup Iteration 3: 16053.824 ops/s # Warmup Iteration 4: 16831.016 ops/s # Warmup Iteration 5: 16920.232 ops/s Iteration 1: 16812.376 ops/s Iteration 2: 16573.129 ops/s Iteration 3: 16345.819 ops/s Iteration 4: 16833.110 ops/s Iteration 5: 16720.344 ops/s Result "example.Main.test2": 16656.956 ±(99.9%) 777.404 ops/s [Average] (min, avg, max) = (16345.819, 16656.956, 16833.110), stdev = 201.889 CI (99.9%): [15879.552, 17434.359] (assumes normal distribution)
# Warmup Iteration 1: 15897.091 ops/s # Warmup Iteration 2: 15017.683 ops/s # Warmup Iteration 3: 15459.037 ops/s # Warmup Iteration 4: 14982.158 ops/s # Warmup Iteration 5: 15466.664 ops/s Iteration 1: 14569.954 ops/s Iteration 2: 15686.090 ops/s Iteration 3: 14593.902 ops/s Iteration 4: 14361.737 ops/s Iteration 5: 14740.184 ops/s Result "example.Main.test3": 14790.373 ±(99.9%) 1996.905 ops/s [Average] (min, avg, max) = (14361.737, 14790.373, 15686.090), stdev = 518.590 CI (99.9%): [12793.469, 16787.278] (assumes normal distribution)