Main points of this paper:

  • The Java language has changed significantly over the past five years
  • There are two major projects that are implementing this change: Valhalla and Amber, which are still ongoing
  • Java continues to maintain its core value of backward compatibility
  • Despite being 25 years old, Java still has a lot of life in the language and platform
  • New technologies such as Graal are helping Java stay at the forefront of programming languages

About five years ago, I wrote an article outlining some ideas about features in other languages that I thought might be beneficial to Java. A lot has happened since then: At that time, Java 8 was the latest release, and now, the latest release is Java 14.

Let’s take a look at each feature in turn to see what its current status is: whether it has been added to Java, is under development, or has no current plans to incorporate it into Java.

Externalize generics

My original prediction excluded Reified Generics. I did not foresee the ambition of the Valhalla project to rebuild the JVM from scratch.

The main objectives of the Valhalla project are:

  • Align JVM memory layout behavior with the cost model of modern hardware;
  • Extending generics to allow abstraction of all types, including primitives, values, and even void; As well as
  • Enable existing libraries (especially the JDK) to evolve compatibly to take advantage of these features.

Hidden in this description is the loaded word “values,” which has evolved into what we today call inline classes.

As a result, materializing generics and primitive specialization have been incorporated into a larger project that promises to fundamentally change the way Java is written and executed.

While deep underlying changes are being made, the project team’s goals include minimizing disruption to existing Java applications and providing a simple, optional way for developers to use Valhalla’s capabilities in their own code.

We should note that Valhalla is still very much an ongoing project, and there is no formal roadmap for when it will be delivered.

Verdict: Ongoing (as part of Valhalla project)

Unsigned arithmetic

The possibility of supporting this feature has been discussed repeatedly throughout Java’s history, but the process of introducing it involved a lot of complexity.

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

There has not been any satisfactory consensus on these issues, so Java still does not include unsigned arithmetic, and one notable aspect of the Valhalla project is that it does not include support for unsigned arithmetic.

Verdict: not yet considered

Array long index

The size of Java arrays is limited by a simple fact of their design: they are indexed by ints. This means that an array is limited to 2^31 elements (remember that ints are signed), or about 2 billion items.

As originally envisioned, the idea of using long instead of int would allow developers to create and manipulate larger arrays. However, since the original “Missing features” article, the community’s focus in this area has shifted to providing easy access to large arrays stored off-heap.

There are many reasons for this. Ease of interoperation with non-Java libraries, including machine learning and a host of other applications, is an important reason. However, there is also the question of how useful a large heap array is. Large, multi-gigabit arrays in and out of the Java heap can generate significant replication costs and potentially cause serious headaches for the JVM’s garbage collector.

For these reasons, large arrays are considered in the context of out-of-heap support, and the concept has been incorporated into the Panama project, where the feature is under active development.

Verdict: In progress (as part of project Panama)

More expressive import syntax

Even at the local (or file-scoped) level, there is no serious attempt to extend the scope of the import syntax or introduce type aliases.

Verdict: not yet considered

Set literal

Static methods on interfaces have been added in Java 9, and collections have been updated to include factory methods for collections. They play the role of Collection Literals in Java:

1 var ls = List. Of (1, 2, 3);Copy the code

This change also introduces a new implementation of the collection interface, as factories play the role of literals. These implementations are immutable, because reusing an existing mutable collection (such as an ArrayList) would violate the programmer’s expectation that the values should behave like literals.

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

Judgment: Delivered (as factory method)

Algebraic data type

Algebraic Data Types in Java are being delivered. This feature includes two major additions to the type system: Records and Sealed Types, and pattern matching, which is a very important new syntax.

Java 14 provides previews of both aspects, specifically: Records, which in Java are essentially named tuples; And the initial components for pattern matching.

The new features that make up the pattern matching section are Java’s first pattern form: the Instanceof pattern and standardized versions of switch expressions.

The second is Scaffolding, which will eventually support the introduction of generic pattern matching, possibly in a similar way to the matching expressions Scala programmers are familiar with.

There are a number of steps that need to be performed before the feature is fully delivered: records and schemas are still only in preview state. Therefore, further JEP (including JEP 375, which extends the Instanceof pattern to destruct records) is needed to flesh out the overall pattern matching.

With the advent of Java 14, key Jeps (including JEP 375 and JEP 360, which introduced the sealing type) were not the target of any particular Java release.

Despite the lack of a concrete roadmap, it is likely that the entire algebraic data types and pattern matching mechanism will be delivered in a standardized form in time for the next LTS release (Java 17 in September 2021).

Verdict: Ongoing (as part of the Amber Project)

Structure type

Java’s type system has evolved to some extent since Java 8, but not in practice toward a common structural type. For example, when designing a record, structure types are explicitly rejected in order to make the record a named type.

This reinforces the idea that the names we give to types have great power and importance, and that Java records are defined by more than just the number and types of their components.

The one small place in Java where something like structural types still looms is in Java’s unrepresentable types. In fact, these are just an extension of the examples originally discussed in the 2015 article.

In this example, we construct an Object that looks like a structure type (Object +), but can only use it in a single expression because there is no representable type that can be used as an assignable variable type.

Since Java 10, the language has had an extended form of type inference, which uses var to reduce boilerplate in assignments. We can use this feature to http://extend the scope”> extend scope, where we can call other methods defined in this way on types. However, this is limited to methods in which type inference occurs. The special type of VAR inference cannot precisely cross method boundaries because it is unrepresentable.

In fact, these particular cases are not true structural types, and there is no intention of introducing them. Java’s design is too attractive for names and named types.

Verdict: Considered but dismissed

Dynamic call point

Over the past five years, the use of InvokeDynamic has expanded considerably, albeit only in the JDK and a few technically mature external libraries.

As stated in the article, “The Java language has no keywords or other structures to create a generic Invokedynamic call point.”

Suggestions that the Dynalink library could be extended to take on this role were never taken up, and in fact the Nashorn Javascript implementation that produced Dynalink itself is now deprecated and can be removed from Java 15 (although Dynalink itself will remain).

The libraries that do use dynamic call points are implemented through the MethodHandles API, which will be slightly easier to use in 2020, but still out of reach for most Java programmers.

The difficulty of finding a balance between flexible dynamic invocation without causing too many runtime problems and compelling language-level usage has proven to be enormous, at least for now.

Verdict: not yet considered

What did I miss?

Over the past five years, there have also been some projects and trends that I did not predict or address in the original article. Perhaps the most important of these are:

  • The extent and scope of the Valhalla project
  • Amber project
  • Java’s latest release model
  • Graal and GraalVM
  • The rise of Kotlin

A few examples:

Although the Valhalla project was launched in 2014, it has gained momentum and grown dramatically in the following years. It is already the most ambitious and biggest change to Java to date. Valhalla promises to change every aspect of the Java platform: from the way memory and values are represented in the VM, to the type system and generics, to the library level and language-level syntax.

The project aims to align Java with the current and future state of hardware and provide performance and other improvements that simply cannot be addressed alone. Instead, Valhalla’s goal is to move the state of the Java platform from its current position, which we can think of as a local maximum, to a position that is more appropriate as the foundation of the platform for decades to come.

Initial research is always hard to predict, so the rise of Graal also surprised me, but not surprising. As with many other fascinating concepts, the basic concept is pretty simple once you get the hang of it.

Java’s commonly used JIT compilers are written in C++ code and execute on special, dedicated threads for the JVM. Graal starts with a simple idea: What if the JIT compiler is written in Java and the compiler thread is actually running a second copy of the Java interpreter?

A JIT compiler that interprets the pattern will have the same characteristics as the current JIT. So it can compile any class file into machine code. We should expect it to be slower than existing C++ compilers, but it won’t behave differently, just in terms of performance.

To boil this idea down to a logical conclusion, it means that the interpreted schema JIT can compile the class files that make up the JIT itself. Once warmed up, it can replace itself and run with the same performance as the original native JIT.

This intriguing idea turned out to be the starting point for a whole new class of technologies, including native compilation (AOT) for Java and a whole new multilingual virtual machine (GraalVM) capable of running many different languages.

conclusion

Over the past five years, the Java platform has become increasingly complex, with many new languages and virtual machine (VM) features delivered or under development. Assuming current trends continue, the community is likely to be most interested in the standardized set of features offered in Java 17, due for release in September 2021.

This will be a very different Java than the Java we initially looked at in 2014, and while some features have already been delivered, it seems clear that others are unlikely to be implemented, and some are implemented in a completely different form. We look forward to seeing how the Java language and platform will evolve over the next five years, especially in areas that we can’t yet predict.