Strings Just Got Faster

StableValue, Records, and Value Classes

  • Main confusion: how StableValue differs from records and upcoming value classes, all of which carry immutable data.
  • Clarifications:
    • StableValue is about lazy, exactly-once initialization of a field whose value is then guaranteed not to change.
    • Records/value classes are about what the data is (transparent, immutable, possibly identity‑less), not when it’s initialized.
    • You can put a record or value class inside a StableValue; they solve different problems.
  • Compared with Kotlin’s lateinit: Kotlin simulates this at the language level; StableValue expresses a promise directly to the JVM, allowing stronger JIT optimizations.

@Stable, Final, and Constant Folding

  • final is an access modifier and historically could be broken via reflection, so JIT often can’t fully trust it.
  • @Stable (internal) and user-level StableValue<T> explicitly promise the JVM that, once written, the value will never change.
  • This enables aggressive constant folding and propagation, even through layers of indirection and lazy initialization.
  • Java records now forbid reflective mutation of final fields; longer term the JVM may “trust” more finals by default.

String.hashCode and Immutable Maps

  • String.hashCode() has long cached its result in a field; the change is that this hash field is now treated as stable.
  • For constant String keys in immutable maps (e.g., Map.of), the JVM can:
    • Inline hash computation and bucket index.
    • Potentially eliminate the map lookup entirely and substitute the value directly.
  • Discussion explores how far this can go in the presence of collisions; consensus: constant folding can still significantly simplify immutable map access, though details depend on implementation.

Security and Hash Randomization Debate

  • Some are surprised Java’s string hash isn’t randomized, given hash-flooding DoS attacks.
  • Others argue:
    • Java mitigates collision attacks in HashMap via tree-based buckets and input limits in frameworks.
    • Changing the hash contract or algorithm now would break compatibility.
    • If you need collision-resistance, you should use specialized collections or hashes.

Performance Impact and Scope

  • Questions about real-world gains: likely small per-service, but may matter at scale and in string-heavy paths (HTTP headers, maps keyed by strings).
  • Kotlin/Scala and other JVM languages benefit automatically, as they use java.lang.String.
  • Some skepticism about the example in the article (map of String to native calls), but others note optimizers must handle “bad” or non-hand-tuned code too.

API Design and Ergonomics

  • Some like the power of StableValue but find the API names (orElseGet) and wrapper-style usage awkward.
  • Suggestions appear for more concise language-level syntax for lazy stable fields; JEP currently favours a library/JVM mechanism over new syntax.