Introducing Java 15
Hello, everyone, and thank you for joining me in this article on What’s New in Java 15. I’ll be guiding you through the highlights and new features of Java 15 in this article. Compared to the previous 2 releases, Java 15 has quite a lot going on. So let’s see what’s in store for us.
In the first module, which you are currently watching, we’ll set the scene around the Java 15 release and see how it fits in around the bigger plans for the Java platform. We will also take a look at some features that are deprecated in this version of Java. Then we’ll look at a major addition to the Java language, which will change the way you work with multiline strings in Java. Text blocks will allow you to work with multiline strings in a much easier way in Java source code. Then we’ll look at 3 very exciting preview language features that are added in Java 15.
You’ll learn about records, sealed classes, and pattern matching using instanceof. Last, even though we’ll spend quite a bit of time on the language features that we just discussed, there are also many JVM improvements that are worthwhile to know about. That’s why we’ll turn our attention to these JVM improvements in the last module of this article.
Especially in terms of low latency garbage collection, a lot is happening in Java 15, so I definitely recommend sticking with this article all the way until the end. Now, during this reading this article, you’ll see several hands on demos, and if you’d like to follow along with those, you should download JDK 15 first. You can find the OpenJDK build for Java 15 at the URL shown here.
The release date for Java 15 is September 15, 2020, so make sure that you download this JDK version to start using it yourself. It’s also good to get a sense of perspective of where this Java 15 release comes in. Java 15 is the second Java release of 2020, and it is one of the many 6 monthly releases that we got since Java 9. Before Java 9, there used to be 3 or 4 years between Java releases. However, as of Java 10, the JDK team switched to a time based schedule, where they release a new version of Java every 6 months. This release schedule has been kept very well in the last years. But the fact that Java is released every 6 months doesn’t necessarily mean that everyone also upgrades to a new version of Java every 6 months.
Every Java release in between 11 and 17 is a full fledged Java release, with new language features, deprecations, removals. So even if you do not end up using this particular version of Java in production, it’s very good that you keep track of what’s happening in Java and see what’s coming for the next LTS release. Before we move on to Java 15 itself, I’d like to give you a quick rundown of all the big changes that happened in Java since Java 8 up till this version. A lot of people and organizations are currently still developing on Java 8, but so much has happened, starting with Java 9, which introduced a module system into the Java language and the Java platform.
This module system was used to modularize the JDK itself, but you can also use it to modularize your own applications and have explicit dependencies and strong encapsulation within modules for your own components. Another striking change in Java 10 was the addition of type inference. As of Java 10, you have the option to omit types for local variables inside methods and instead replace them with var, where the Java compiler infers the type for you. On the API side of things. Java 11 introduced an all new HttpClient API. This replaces the very old HTTP URL connection that was in the JDK. Now a lot of people were using other libraries like Apache HTTP client and OkHttp because the JDK API was so horrible to work with, but now we have a modern alternative in the JDK itself that supports HTTP 2, WebSockets, is reactive, and has all the goodies that you’d expect from a modern HttpClient.
There have been continuous improvements to the JVM as well in terms of performance and security, so all in all, a lot has happened. And even in Java 13 and 14 there were some language additions. Now, if you’ve not seen this yet, I highly recommend checking out the What’s New in Java courses for the versions that you’ve not seen yet. It will really show you how vibrant and alive the Java platform is. There’s also the Java Fundamentals: HttpClient course, which dives more deeply into the HttpClient API that we just talked about. That being said, this course is about Java 15, so we’ll first have a look at some cleanups that happened in JDK 15, because, thankfully, evolving the Java platform doesn’t only mean adding new features but also cleaning up some old and deprecated features.
Deprecations & Removals
Let’s have a look at some of the deprecations and removal that happened in JDK 15. And there’s been some spring cleaning. I really like it. Why? Well, if you maintain software, you know that it tends to grower bigger and bigger and that it gets harder to maintain. And the same happens to the Java platform itself. However, if you build your own software and you depend on some of these deprecated and removed technologies, you need to be aware and start planning for this.
One of the big changes in the JDK project as of Java 15 is the removal of two JDK ports. Now, of course, the main platforms, Linux, Mac, and Windows are not affected. However, the ports of the JDK to the Solaris operating system have been removed. The same applies for the JDK ports for the SPARC CPU architecture. It’s maybe a bit sad to see the end of the line for these once innovative technologies from the old Sun Microsystems days.
But maintaining support for these now fringe technologies was putting an undue burden on the JDK developers going forward. If you’d like to know more about the removal of these two ports and the rationale behind it, you can read the Java enhancement proposal, or JEP 381.
It contains all the details about the fate of the Solaris and SPARC support in the JDK. Another older technology that is getting some cleanup in JDK 15 is RMI. RMI stands for remote method invocation, and it’s a technology for building distributed systems using Java. Now rest assured, the RMI technology itself is not deprecated or removed. It is just a specific part called activation. RMI activation was a technology to persist and later activate remote objects without having a JVM running continuously. It was already an optional part of RMI since Java 8, and it was hardly used. Therefore, the package java.rmi.activation and all contained types therein are now marked as deprecated for removal, meaning these types will disappear in the future release of Java. Besides deprecating the Java API, an associated tool in the JDK called rmid is also deprecated. This was the RMI activation system daemon, which was listening for activation requests. Another cleanup in RMI is the removal of the rmic tool.
This is not related to the activation deprecation that we just talked about, but this RMI stock compiler was already deprecated for a longer time. If you’re using RMI, you should be using dynamic steps, not statically generated ones from the RMI compiler. Dynamic steps for RMI have been available since Java 5, so there has been plenty of time to adopt it. In general, I would say it’s even questionable if you should use RMI from new systems development at all. We’ve got more modern tools nowadays to build distributed systems and to do communication between services. However, it’s good to know that RMI is still there for existing applications that use it, and code using RMI won’t break on Java 15. Still, if your RMI code depends on the activation API, you should definitely get rid of that. There’s one more big removal in JDK 15 that I would like to highlight.
One of these new features is quite small but very useful. The official name of the feature is helpful NullPointerExceptions. And as you’ve probably all experienced, NullPointerExceptions are generally not that helpful. So what does this mean? Let’s say we have a piece of code, as shown here, where we have an expression on a single line that does multiple change invocations. Now if any of these subexpressions return null, you will get a NullPointerException like this, telling you and null was encountered somewhere on line 5, which is where this piece of code lives. Unfortunately, this doesn’t really help us because we don’t know whether the invocation to method a returned null, or the method b returned null, or the field c was null.
So we’ll still have to do a lot of manual debugging. Java 14, the previous release, introduced a new flag called ShowCodeDetailsInExceptionMessages, which, when you enable this, provided a vastly improved version of the exception. When you run the same code with this flag enabled in Java 14, you will see that the NullPointerException has much more detail. It says that it cannot invoke the doSomething method because the subexpression ending with c is null. So now we know that the field c on the object returned by the method b is the culprit here. So why am I talking about a Java 14 feature here, we’re talking about Java 15?
Well, as a matter of fact, in Java 15 you do not have to add this flag anymore. It is enabled by default. That means that just by switching to JDK 15, your NullPointerExceptions will become more informative. And I would say, what’s not to like about that? Just to give you a little bit more of a taste how useful this feature is, let’s look at two other examples. In the first example, we have a local variable a initialized to null. Then we’re trying to set the field b on this null value, which, of course, won’t work because a is null. Now running this code on JDK 15 will give the exception saying cannot assign field b because a is null. This message pretty explicitly points out what the issue is. Now the issue was, of course, already easy to spot in this code because the two lines were just above each other, but just imagine that the initialization of the value is far away from the use of the value, and then it suddenly becomes pretty convenient if the NullPointerExceptions are this explicit. Last, the exception messages also work very nicely with arrays. Here we initialize a multi dimensional array with the first value being a null, and then we try to assign a value to this array of these two dimensions.
Again, the NullPointerException that results here is pretty explicit. It says, cannot store to object array because a is null. And yes, these NullPointerExceptions are indeed helpful. If for some reason you do not want to have these messages in your NullPointerExceptions and you want to revert to the previous behavior, you can use the same flag that we saw earlier, ShowCodeDetailsInExceptionMessages, only instead of using it with a plus, you use it with a minus, telling the JVM to revert to the old behavior of showing non-informative NullPointerException messages. This feature also has its own Java Enhancement Proposal, 358, which you can read for more details.