Project Valhalla: A look inside Java’s epic refactor

In Java, everything is an object—except primitives like int. Turns out that small caveat has had big implications for the language, which have compounded over the years. This seemingly minor design decision causes problems in key areas like collections and generics. It also limits certain performance optimizations. Project Valhalla, the Java language refactor, aims to correct these issues. Valhalla project lead Brian Goetz has said that Valhalla will “heal the rift between primitives and objects.”

It’s fair to say Project Valhalla is an epic refactor, seeking to address technical debt buried in the platform since Java’s inception. This thoroughgoing evolution proves that Java is not only a classic but remains at the forefront of programming language design. Let’s take a look at the key technical components of Project Valhalla and why they are so critical to the future of Java.

Performance issues in Java

When Java was first introduced way back in the ’90s, it was decided that all user-created types would be classes. Only a handful of primitive types were put aside as special. These were not handled as pointer-based class structures but directly mapped to operating system types. The eight primitive types are int, byte, short, long, float, double, boolean, and char

Directly mapping these variables to the operating system was better for performance because numerical operations performed better when divested of the referential overhead of objects. Moreover, all data ultimately resolves to these eight primitive types in a program. Classes are just a kind of structural and organizational layer that offers more powerful ways of handling primitive types. The only other kind of structure is the array. Primitives, classes, and arrays comprise the whole range of Java’s expressive power.

But primitives are a different category of animal from classes and arrays. As programmers, we have learned to deal with the differences intuitively. Primitives are pass-by-value while objects are pass-by-reference, for example. The why of this goes quite deep. It comes down to the question of identity. We can say that primitive values are fungible: int x = 4 is the integer 4, no matter where it appears. We see this distinction in equals() vs ==, where the former is testing for the value equivalence of objects and the latter is testing for identity. If two references share the same space in memory, they satisfy ==, meaning that they are the same object. Any ints set to 4 will also satisfy ==, whereas int doesn’t support .equals() at all.  

The Java virtual machine (JVM) can take advantage of the way primitives are handled to optimize how it stores, retrieves, and operates on them. In particular, if the platform determines that a variable is not altered (that is, it’s a constant or immutable) then it is available to be optimized.

Copyright © 2023 IDG Communications, Inc.

Source link

Leave a Reply

Your email address will not be published. Required fields are marked *