Project Valhalla Goes Mainstream: Using Value Types in Production Editorial Team, December 19, 2025December 25, 2025 For over a decade, the name “Project Valahalla” has floated through the Java ecosystem as a beacon of future potential—a promise of radical performance improvements and a more expressive type system. Often discussed in theoretical terms or relegated to JVM internals, it felt like a distant horizon. That horizon has now arrived. With the preview features in recent JDK releases, Valhalla’s cornerstone achievement—value objects—is transitioning from research prototype to a practical tool for production-minded developers. This isn’t just about cutting-edge benchmarks; it’s about writing more predictable, efficient, and scalable Java code. Table of Contents Toggle What Are Value Types, Really?The Production Payoff: Beyond TheoryNavigating the New Landscape: Key Concepts for DevelopersA Practical Example: From Concept to CodeChallenges and Considerations for AdoptionThe Future is Flattened What Are Value Types, Really? At its core, Project Valhalla aims to solve a fundamental mismatch in Java’s object model: the semantic and performance cost of treating all objects as identity-heavy, heap-allocated references. For many data-centric classes—think complex numbers, geographic coordinates, currency amounts, or range objects—identity is irrelevant. An OrderId with value 12345 is identical to any other OrderId(12345). They are defined solely by their state. Before Valhalla, we mimicked these with classes, but each instance carried the overhead of an object header (for locking, garbage collection, and identity hash code) and required pointer indirection. This fragmented memory and crushed cache locality occur when processing millions of such objects. We resorted to awkward workarounds: parallel arrays of primitives, mutable “holder” objects, or sacrificing type safety entirely. Value types, declared with the new value modifier (or as a record class, which is implicitly a value class), break this mold. They are identity-less aggregates. The JVM can flatten them—storing their fields directly within their container, be it another object or an array—just as it does with primitive int or double. They are “codes like a class, works like an int.” See also WebAssembly (Wasm) and Java: A New Frontier for the BrowserThe Production Payoff: Beyond Theory The academic benefits are clear: eliminated header overhead, improved cache locality, and reduced garbage collection pressure. But what does this translate to in a production service? 1. Memory Efficiency at Scale: Consider a financial trading application that processes millions of Trade objects per second. Each Trade might contain several Money objects (amount and currency) and PricePoint objects (timestamp and value). In the traditional model, each of these small objects is a separate heap entity with 12-16 bytes of overhead. Flattened as value types, they become mere field groupings within the Trade. We’ve seen realistic scenarios where aggregate memory footprint drops by 40-50%, directly reducing heap size requirements and GC frequency. 2. Data Structure Revolution: The most dramatic impact is on collections. An ArrayList<Point> where Point is a value class no longer stores an array of references to scattered Point objects. It stores a contiguous block of memory containing alternating x and y values. This transforms performance for numeric, scientific, and graphics workloads. Iteration becomes a sequential memory scan, which CPUs love. The performance profile begins to resemble languages like C or Rust for these data-oriented tasks, while retaining Java’s safety and abstraction. 3. Safer, More Expressive APIs: Value types provide a path to true “wrapper” classes without the guilt. You can now create a UserId, AccountNumber, or NonNegativeDouble as a proper, immutable type with compile-time checking. Before, the performance penalty discouraged this, leading to primitive obsession and error-prone code. Now, you get domain-rich types with near-zero runtime cost. It enables a style of programming where the type system carries more of the design logic. See also From Monolith to Microservices: A Pragmatic Migration GuideNavigating the New Landscape: Key Concepts for Developers Adopting value types requires understanding their semantics: Final and Immutable: Value classes are implicitly final and their fields are final. They are immutable aggregates. == and equals: With no identity, == performs a bitwise comparison of the flattened fields (a “pure” value comparison). For most purposes, == and equals behave identically, though equals is still provided for API consistency. Nullability: A value object reference cannot be null in its flattened form. The type system enforces this through new null-restricted types, eliminating a whole category of runtime errors. Compatibility: This is a crucial design triumph. Value types are a subclass of java.lang.Object. They can implement interfaces and be used in existing reflection and serialization frameworks. Your List<CurrencyUnit> still works; it just becomes vastly more efficient. A Practical Example: From Concept to Code Let’s model a simplified pixel for an image processing pipeline. java // Pre-Valhalla: A typical immutable class. public class ClassicPixel { private final short red, green, blue, alpha; // Constructor, getters, equals, hashCode... } // An array of 10 million pixels: 10M objects, 10M headers, fragmented memory. // With Valhalla (preview): public value class Pixel { short red; short green; short blue; short alpha; public Pixel(short r, short g, short b, short a) { this.red = r; this.green = g; this.blue = b; this.alpha = a; } } // An array of 10 million Pixel instances is essentially a contiguous short[40_000_000]. Operations like applying a color filter become loops over dense, linear memory. The performance difference isn’t incremental; it’s transformative. Challenges and Considerations for Adoption Valhalla is not a silver bullet, and production use requires care. Migration Path: You cannot magically annotate an existing class as value and expect everything to work. If your class relied on identity (synchronization, default hashCode, serialization identity), it is not a candidate. This is a deliberate design choice: value semantics must be opted into where they are correct. New Mental Models: Developers must internalize the difference between identity and value objects. Debuggers and profiling tools will need to adapt to show flattened representations. Preview Feature: As of JDK 23, value classes are still a preview feature. They require the --enable-preview flag. For production, you’d typically wait for finalization in a future LTS release (likely JDK 25 or 27), but now is the time to start prototyping, benchmarking, and educating teams. See also NoSQL with Java: A Guide to Redis, MongoDB, and Cassandra DriversThe Future is Flattened Project Valhalla’s arrival marks a paradigm shift for Java. It closes the last major performance gap between Java and natively compiled languages for data-intensive workloads, while reinforcing Java’s strengths in robustness and maintainability. It enables architectures that were previously impractical—real-time systems processing vast data streams, in-memory databases holding billions of entities, and microservices with tighter memory budgets. The journey from a research project named after the mythical hall of slain warriors to a mainstream production tool is complete. The warriors—the developers battling performance bottlenecks and memory limits—now have a powerful new weapon. The mandate for senior engineers and architects is clear: begin exploring value types in your performance-critical domains. Prototype, measure, and prepare. The future of high-performance Java is not just faster; it’s simpler, safer, and elegantly flat. Java