import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; /** * JEP 531, Lazy Constants (third preview), against the JDK 27 API. * *

A lazy constant is a value that is computed the first time somebody asks for it and never again, * even when many threads ask at once. The JVM can then treat it like a {@code final} field. What changed * since JDK 26: {@code orElse(...)} and {@code isInitialized()} are gone (see broken/Lazy26.java), and * {@code Set.ofLazy(...)} arrived next to {@code List.ofLazy} and {@code Map.ofLazy}. * Explained in docs/06-lazy-constants.md. Compile and run with --enable-preview. */ public class LazyDemo { static final AtomicInteger INITIALISATIONS = new AtomicInteger(); /** The expensive thing: pretend this reads a file and parses it. */ record Settings(String region, int poolSize) {} static Settings loadSettings() { INITIALISATIONS.incrementAndGet(); System.out.println(" (loading settings on " + Thread.currentThread().getName() + ")"); return new Settings("ap-south-1", 16); } static final LazyConstant SETTINGS = LazyConstant.of(LazyDemo::loadSettings); /** Identity hashes and lambda addresses change on every run; blank them so the transcript is stable. */ static String tidy(Object o) { return o.toString().replaceAll("@[0-9a-f]+", "@...").replaceAll("/0x[0-9a-f]+", "/0x..."); } public static void main(String[] args) throws Exception { System.out.println("--- a lazy constant computes once, on first use"); System.out.println("toString before first get(): " + tidy(SETTINGS)); Settings first = SETTINGS.get(); Settings second = SETTINGS.get(); System.out.println("toString after first get(): " + tidy(SETTINGS)); Check.that(first == second, "get() returns the same instance every time"); Check.that(INITIALISATIONS.get() == 1, "the supplier ran exactly once"); System.out.println("--- and once even when 64 threads race for it"); var raced = LazyConstant.of(() -> { INITIALISATIONS.incrementAndGet(); return "computed"; }); int before = INITIALISATIONS.get(); var start = new CountDownLatch(1); try (var pool = Executors.newVirtualThreadPerTaskExecutor()) { for (int i = 0; i < 64; i++) { pool.submit(() -> { start.await(); return raced.get(); }); } start.countDown(); } Check.that(INITIALISATIONS.get() - before == 1, "64 racing threads triggered exactly one initialisation"); System.out.println("--- List.ofLazy: each element is computed on first access"); AtomicInteger listComputations = new AtomicInteger(); List squares = List.ofLazy(5, i -> { listComputations.incrementAndGet(); return "square(" + i + ")=" + (i * i); }); System.out.println("computed so far: " + listComputations.get()); System.out.println("squares.get(3) = " + squares.get(3)); System.out.println("squares.get(3) = " + squares.get(3) + " (second read)"); Check.that(listComputations.get() == 1, "only element 3 was ever computed"); System.out.println("--- Map.ofLazy: the keys are fixed, the values are computed on first access"); AtomicInteger mapComputations = new AtomicInteger(); Map lengths = Map.ofLazy(Set.of("alpha", "beta", "gamma"), k -> { mapComputations.incrementAndGet(); return k.length(); }); System.out.println("lengths.get(\"gamma\") = " + lengths.get("gamma")); Check.that(mapComputations.get() == 1, "only the requested key's value was computed"); System.out.println("--- Set.ofLazy (new in 27): membership is decided by a predicate, on demand"); AtomicInteger setComputations = new AtomicInteger(); Set primes = Set.ofLazy(Set.of(2, 3, 4, 5, 6, 7), n -> { setComputations.incrementAndGet(); return n > 1 && java.util.stream.IntStream.rangeClosed(2, (int) Math.sqrt(n)).noneMatch(d -> n % d == 0); }); System.out.println("primes.contains(7) = " + primes.contains(7) + ", primes.contains(6) = " + primes.contains(6)); Check.that(primes.contains(7) && !primes.contains(6), "the lazy set answers membership using the predicate"); System.out.println("primes = " + new java.util.TreeSet<>(primes)); } }