Definitive Guide To Java 13

Java 13 was released an hour ago and here’s everything you need to know about it, starting with migration considerations and version requirements before getting into the juicy bits: First and foremost the new text blocks, but there are also a few smaller additions like a refinement of switch expressions and a usability improvement for application class-data sharing. Here’s your overview with lots of links to more detailed articles.


If you want to play around with the code yourself, check out the Java X Demo on GitHub.

Migrating to Java 13

I will assume, you’re at least on Java 11. If you’re not, don’t feel bad about it (few projects are), but I recommend to try and change that. Start by reading my Java 11 migration guide and about these lesser known gems in Java 11.

Migrating from Java 11?

If you’re on Java 12, you will update to 13. If you’re on 11, it is less straightforward.

So, assuming you’re on Java 11 or later, the question is whether you will update to Java 13. If you’re already on 12, the answer is easy: Yes, you will. Java 12 is no longer supported and will not see any security fixes.

If you’re on 11 (everybody’s favorite LTS), it is much harder to find an appropriate answer. I discussed this in detail in my Java 12 guide and I won’t repeat it all here. Just as a rule of thumb, the more of the following properties your project has, the more I’d play it safe by staying on 11:

  • runs at customer site on machines you have no control over
  • not containerized, may share JVM with other processes
  • the project has lots of dependencies
  • it is hard to keep dependencies up to date
  • the migrations from 9 to 10 and 10 to 11 were not trivial (removal of Java EE modules aside)

Version Requirements

Here are the most common IDEs’ and build tools’ minimum version requirements for Java 13:

  • IntelliJ IDEA: 2019.2
  • Eclipse: 2019-09 (4.13) with Java 13 Support plugin
  • Maven: 3.5.0
    • compiler plugin: 3.8.0
    • surefire and failsafe: 2.22.0
    • plugins using ASM (e.g. the shade plugin) will likely need to be updated as well
  • Gradle: 6.0

When it comes to compiling to Java 13 bytecode, keep in mind that you will likely have to update all dependencies that rely on bytecode manipulation, e.g. Spring, Hibernate, Mockito, etc.

Preview Features

I wrote a dedicated post on preview features, so I will stick to the very basics here. If you want to use text blocks or switch expressions (see below for details on them), include this in your build tool configuration:

In IntelliJ IDEA, set the language level for your module to 13 (Preview). In Eclipse, find the Java Compiler configuration and check Enable preview features.

Language Features

Here’s the new syntax you get if you upgrade to Java 13.

Text Blocks

Putting strings that span several lines into code has been a pain in Java since its inception. Now, 20-something years later, we finally get easy-to-use multiline strings, called text blocks:

Text blocks start with three quotation marks and a newline (the opening delimiter; the newline is not part of the result) and end with three quotation marks either in the last line of content or on its own line (if the latter, the string ends with a newline). They are accepted in the exact same places where string literals "like this one" are. In fact, after the compiler processed them, they are absolutely indistinguishable from strings created by literals. That means jsonLiteral.equals(jsonBlock) is true and, thanks to String interning, even jsonLiteral == jsonBlock is.

The compiler considers indentation that’s shared across all lines incidental and removes it. Other leading whitespace is considered essential and left in place. For jsonBlock that means that the lines with { and } have no indentation, but the property lines do. There’s lots more to indentation, which I explain in my deep dive into text blocks.

In Java 13, text blocks are a preview feature.

Definite Guide To Text Blocks In Java 13
Programmer’s Guide To Text Blocks (by Oracle)
JEP 355: Text Blocks

Returning Values From Switch Expressions

Switch expressions were introduced in Java 12 and 13 refines them. In 12 you would define return values with break:

In 13, you need to use yield:

I slightly prefer the new variant. While break was easy to adopt for developers already familiar with Java, it was pretty odd. I mean, what is break true trying to tell me? The new (conditional) keyword yield is clearer, and in the future it may show up in other places where values are returned – in fact, Brian Goetz said it would have been used for lambdas if they had thought of the necessity back then.

Due to this change, switch expressions are still in preview.

Definitive Guide To Switch Expressions In Java 13
First Contact with Switch Expressions in Java 12 (video)
JEP 325: Switch Expressions (introduction in 12)
JEP 354: Switch Expressions (refinement in 13)

API Improvements

This is usually the place where I turn to new and updated APIs and tell you about all the small tidbits that will make your life easier. Except… there aren’t very many in 13. Sad.

JDK 12 to 13 API Change Report
Auto-generated release notes

New String Methods

String got three new methods:

  • String::stripIndent behaves just like the algorithm the compiler uses to remove indentation of text blocks.
  • Similarly, String::translateEscapes exposes the compiler’s behavior when translating escape sequences in strings.
  • String::formatted is an instance method reimplementing the static method String::format. That means calling "Value: %s".formatted(value) is equivalent to String.format("Value: %s", value), but a little more convenient.

NIO Improvements

Then there are a few small improvements in the NIO APIs, but I won’t go into detail here – I recommend to check the issues and JavaDoc if the title appear interesting to you:

JDK-5029431: Add absolute bulk put and get methods
JDK-8218418: Files.createSymbolicLink should use SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
JDK-8215467: Files.isHidden should return true for hidden directories on Windows
JDK-8218875: Add FileSystems.newFileSystem(Path, Map<String, ?>) method

Beyond these small additions, I got a big refactoring for you, though.

Socket And ServerSocket Reimplementation

Project Loom will introduce fibers (light-weight threads managed by the JVM) and a part of that is to have all code that blocks take the same paths (because those paths are then changed to no longer block threads). A critical part of the JDK where threads are blocked are the und classes. Their implementation was very old and didn’t line up with Loom’s approach, so in preparation of future changes, this API was reimplemented. This should not be noticeable to us.

Project Loom
JEP 353: Reimplement the Legacy Socket API

New JVM Capabilities

As usual, the JVM sees a fair share if improvements. Here are the most important ones.

JDK-8221431: Support for Unicode 12.1
JDK 13 Security Enhancements (by Oracle’s Sean Mullan)

Creating Class-Data Archives For AppCDS

Application class-data sharing (AppCDS) was made freely available in Java 10 and improved in 12 and 13. It reduces launch times (by 10% to almost 50%) and response time outliers by moving much of the class-loading work out of the program run. Instead of loading class data from JARs when it’s needed, AppCDS prepares an immutable archive file and maps it into memory when the JVM launches. (Or "the JVMs" because the archive can be shared between multiple instances.)

On Java 10, using an archive used to be a three-step process:

  • creating a list of classes to archive
  • creating the archive
  • launching with the archive

Java 12 relaxed this a little by introducing a default archive of JDK classes that is shipped with the JVM and used automatically. But you still had to go through the steps above to create an archive that includes your application classes. This is where Java 13 comes into play.

The new option -XX:ArchiveClassesAtExit tells the JVM to run as usual, but on exit (if it didn’t crash), to write the class-data into the specified file. That can then be used on future program launches:

This approach uses so-called dynamic CDS archives and makes the feature much easier to use. If you care about launch times, give it a shot!

Improve Launch Times On Java 13 With Application Class-Data Sharing
JEP 310: Application Class-Data Sharing
JEP 341: Default CDS Archives
JEP 350: Dynamic CDS Archives

ZGC’s Use Of Memory

Oracle’s Z Garbage Collector (ZGC) is a scalable low latency garbage collector designed to meet pause times that are independent of heap or live-set size (ranging from a few hundred MB to many TB) and stay below 10 ms. In Java 13, heaps size can be 16 TB and ZGC can return unused memory to the operating system. The command line argument -XX:ZUncommitDelay=<seconds> can be used to configure when that happens.

Then there’s a new command line flag -XX:SoftMaxHeapSize that informs the garbage collector to try and limit the heap to the specified size. If it would otherwise run out of memory, it is allowed to use more memory, though, up wo what’s specified with -Xmx. This should work well together with returning unused memory.

JEP 351: ZGC: Uncommit Unused Memory
JDK-8221786: ZGC: Increase max heap size to 16TB
JDK-8222145: Add -XX:SoftMaxHeapSize flag

Major improvements for Shenandoah

Another very interesting garbage collector that sees constant improvement is Red Hat’s Shenandoah, a low-pause GC that performs most garbage collection work concurrently with the running program. This includes concurrent compaction, which means Shenandoah’s pause times are not directly proportional to the size of the heap.

A change in Java 13 is the new load-reference barriers scheme, which offers a much simpler internal implementation, opening up more opportunities for optimizations, which in turn improves performance. One of those optimizations is the removal of separate forwarding pointer word per object, which is supposed to considerably drop the footprint overhead.

Shenandoah also extended its platform support and now runs on all x86_32 platforms plus a few build fixes allows it to be built and used on Solaris x86_64. There are many convenience improvements as well, like changing the default GC threads count, accepting even smaller heap sizes, and better interaction with uncommits.

JDK-8221766: Load-reference barriers
JDK-8222185: Report “committed” as capacity
JDK-8222186: Don’t uncommit below minimum heap size
JDK-8223759: Allow arbitrarily low initial heap size
JDK-8223767: Build on Solaris x86_64
JDK-8224584: Eliminate forwarding pointer word
JDK-8225048: x86_32 support
JDK-8225229: Trim down default number of GC threads


And that’s Java 13 in a nutshell for you:

  • text blocks (preview)
  • yield for switch expressions (preview)
  • dynamic AppCDS archives with -XX:ArchiveClassesAtExit

Now, go forth, download, and have fun!

Share & Follow

You liked this post? Then share it with your friends and followers!
And if you like what I'm writing about, why don't you follow me?

Other Posts