Key Takeaways The Java language has changed notably over the last 5 years

Two major projects that are delivering that change - Valhalla and Amber - are still in flight

Java has continued to maintain its core value of backwards compatibility

Despite being 25 years old, there is still plenty of life left in the language and platform

New technologies, such as Graal, are helping to keep Java at the forefront of programming languages

Almost five years ago, I wrote an article outlining some feature ideas from other languages that I felt could be of benefit to Java. A lot has happened since then — at that time, Java 8 was the newly minted release, whereas the most recent version is now Java 14.

Let’s take a look at each feature in turn and see what its current status is: whether it has been added to Java, is on the way, or is not currently planned for inclusion.

Reified generics

My original predictions ruled out reified generics. I did not foresee the ambition that Project Valhalla has for remaking the JVM from the ground up.

Related Sponsored Content Demystifying Microservices for Jakarta EE & Java EE Developers

Project Valhalla’s major goals are:

aligning JVM memory layout behavior with the cost model of modern hardware;

extending generics to allow abstraction over all types, including primitives, values, and even void ; and

; and enabling existing libraries, especially the JDK, to compatibly evolve to fully take advantage of these features.

Buried within this description is the loaded word "values", which has evolved into the feature that we know today as inline classes.

Reified generics and primitive specialization have thus been subsumed into a much larger project that promises to fundamentally change the way that Java is written and executed.

Despite the deep low-level changes that are being made, the goals of the project team include minimizing disruption to existing Java applications and providing an easy, opt-in approach for developers who use Valhalla capabilities in their own code.

We should note that Valhalla is still very much a work in progress — and there is still no official roadmap for when it might be delivered.

Verdict: ON THE WAY (as part of Project Valhalla)

Unsigned arithmetic

The possibility of supporting this feature has been repeatedly discussed over Java’s history, but there are a number of complexities involved in introducing it.

For example, there is the question of how signedness should be represented in the Java type system, and whether it should be visible at JVM bytecode level or not.

These issues have not reached any satisfactory consensus and so Java still does not contain unsigned arithmetic — and one notable aspect of Project Valhalla is that it does not include support for unsigned arithmetic.

Verdict: NOT BEING CONSIDERED

Long indices for arrays

Java’s arrays are constrained in size by a simple fact of their design: they take an int as their index. This means that an array is limited to 2**31 elements (remembering that ints are signed), or roughly 2 billion entries.

As originally envisaged, the idea of using a long instead of an int would allow developers to create and manipulate much larger arrays. However, since the original "Missing Features" article, the community’s focus in this area has shifted towards providing easy access to large arrays stored off-heap.

There are several reasons for this — ease of interop with non-Java libraries (including machine learning and other number-heavy applications) is one important one. However, there are also questions about how useful large, on-heap arrays would even be. Huge, multi-gig arrays would have significant copy costs when moving in and out of the Java heap and could potentially cause serious headaches for the JVM’s garbage collector.

For these reasons, large arrays are mainly thought of in the context of off-heap support, and the concept has been incorporated into features under active development within Project Panama.

Verdict: ON THE WAY (as part of Project Panama)

More expressive import syntax

No serious attempts have been made to expand the scope of import syntax or to introduce type aliasing, even at the local (or file-scoped) level.

Verdict: NOT BEING CONSIDERED

Collection literals

Static methods on interfaces were added in Java 9, and the collections were updated to include factory methods for collections. These play the role of collection literals in Java:

var ls = List.of(1,2,3);

As the factories are playing the role of literals, this change also introduced new implementations of the collection interfaces. These implementations are immutable, because to reuse the existing mutable collections (such as ArrayList) would have violated the programmer expectation that these values should behave as if they were literals.

More intrusive solutions, such as directly introducing new literals into the language syntax, were not pursued.

Verdict: DELIVERED (as factory methods)

Algebraic data types

Algebraic data types in Java are in the process of delivery. The feature consists of two major additions to the type system: records and sealed types as well as pattern matching, a substantial new piece of syntax.

Java 14 delivers a preview version of two of these aspects — specifically, records, which in Java are essentially named tuples, and the initial components of pattern matching.

The new features that make up the introductory pieces of pattern matching are the first form of pattern in Java: the instanceof pattern and a standardized version of switch expressions.

The second of these is the scaffolding that will ultimately enable the introduction of general pattern matching, in a similar way to the match expressions with which Scala programmers may be familiar.

There are still many more steps to take before this feature is fully delivered — records and patterns are still only in preview. Further JEPs, including JEP 375, which extends the instanceof pattern to allow deconstruction of records, are required to flesh out pattern matching as a whole.

As of the arrival of Java 14, key JEPs — including both JEP 375 and JEP 360, which introduces sealed types — are not targeted for any specific Java version.

Despite this lack of a concrete roadmap, it is likely that the entirety of the algebraic data types and pattern-matching mechanism could be delivered in standardized form in time for the next LTS release, which is Java 17 in September 2021.

Verdict: ON THE WAY (as part of Project Amber)

Structural typing

Java’s type system has evolved somewhat since Java 8, but in practice there has been no significant move towards general structural typing. For example, when records were being designed, structural typing was explicitly rejected in favor of making records nominal types.

This enforces the idea that the name that we give to a type has power and importance, that Java records are defined by more than just the number and types of their components.

One minor place where something that resembles structural typing continues to be vaguely visible in Java is in Java’s non-denotable types. These are really just an extension of the example originally discussed in the 2015 piece.

In that example, we construct something that looks like a structural type (Object + <some method>) but can only use it within a single expression because there’s no denotable type that we can use as the type of a variable to assign the value to.

Since Java 10, the language has had an extended form of type inference that uses var to reduce boilerplate in assignments. We are able to use this capability to extend the scope in which we may call additional methods defined on a type in this way. However, this is limited to the method in which the type inference occurs. The special type that var infers cannot be propogated across method boundaries precisely because it is non-denotable.

In reality, these special cases are not true structural typing, and there is no intention of introducing it. The gravitational pull of Java’s design attraction to names and nominal typing is just too strong.

Verdict: CONSIDERED BUT REJECTED

Dynamic call sites

The last five years have seen a large expansion in the use of invokedynamic, although only within the JDK and a small number of technically sophisticated external libraries.

It is still the case that "the Java language does not have a keyword or other construct to create general-purpose invokedynamic call sites" just as the original article stated.

The suggestion that the Dynalink library could be expanded to take up this role never came to pass, and, in fact, the Nashorn Javascript implementation that produced Dynalink is now itself considered deprecated and could be omitted from Java 15 (although Dynalink itself will remain).

Those libraries that do make use of dynamic call sites do so via the MethodHandles API that, while slightly easier to use in 2020, is still out of reach of most Java programmers.

The difficulty of finding a balance between flexible dynamic invocation that does not cause too many runtime problems and compelling language-level usage has proved to be too great, at least for the time being.

Verdict: NOT BEING CONSIDERED

What Did I Miss?

The last 5 years have also seen the emergence of a number of projects and trends that I did not predict or address in the original article. The biggest of these are perhaps:

Extent and scope of Project Valhalla

Project Amber

New Release Model for Java

Graal and GraalVM

Rise of Kotlin

To pick out a couple of examples:

Although Project Valhalla was started in 2014, it has gained momentum and expanded enormously over the intervening years. It has become the most ambitious and biggest change that Java has ever seen. Valhalla promises to modify every aspect of the Java platform - from the way that memory and values are represented within the VM, through the type system and generics, and up into the library level and language syntax.

This project aims to align Java with the current and future state of hardware and to offer performance and other improvements that simply cannot be addressed piecemeal. Instead, Valhalla aims to move the state of the Java platform from its current position (which we can think of as a local maxima) to a place that is much better suited to be the basis of a platform for the coming decades.

Original research is always hard to predict, and so it is perhaps unsurprising that the rise of Graal also caught me by surprise. The basic idea is, like many other compelling concepts, very simple once you’ve grasped it.

Java’s usual JIT compiler is written in C++ code and executes on special dedicated threads within the JVM. Graal starts from a simple idea: What if, instead, the JIT compiler was written in Java and the compiler threads were actually running a second copy of the Java interpreter?

The interpreted-mode JIT compiler would be as capable as the current JIT - so it could compile any class file to machine code. We should expect that it would be slower than the existing C++ compiler, but it would not differ in its behaviour, only in performance.

Taking this idea to its logical conclusion, this means that the interpreted-mode JIT could compile the class files that make up the JIT itself. Once it had warmed up, it could replace itself and run at the same performance as the original, native JIT.

This intruiging idea turns out to be the starting point for a major class of new technologies, including native compilation of Java (AOT) as well as a new polyglot virtual machine (GraalVM) capable of running many different languages.

Conclusions

The Java platform has grown in sophistication over the last five years, with many new language and VM features delivered or in flight. Assuming current trends continue, the community is likely to be most interested in the set of standardized features that will be available in Java 17 (due in September 2021).

This will be a very different Java than the one that existed in 2014 when we made our original observations, and while some features have been delivered it seems clear that certain others are unlikely ever to arrive and still others have been realized in a very different form. We look forward to seeing what the next five years will bring for the Java language and platform, and especially the aspects that we are unable to predict right now.

About the Author

Ben Evans is a co-founder of jClarity, a JVM performance optimization company. He is an organizer for the LJC (London's JUG) and a member of the JCP Executive Committee, helping define standards for the Java ecosystem. Ben is a Java Champion; 3-time JavaOne Rockstar Speaker; author of "The Well-Grounded Java Developer", the new edition of "Java in a Nutshell" and "Optimizing Java" He is a regular speaker on the Java platform, performance, architecture, concurrency, startups and related topics. Ben is sometimes available for speaking, teaching, writing and consultancy engagements - please contact for details.