Introduction to Java 13 features

Java 13 features Language Architect Brian Goetz announced are finally generally available. These features range from reimplementation of old and hard-to-deal-with socket API to the most important (at least for me) changes that make Java code more readable, and rapid. The following Java Enhancement Proposals are delivered in JDK 13:

Get Gayle Laakmann - Cracking the Coding Interview - 4th, 5th and 6th edition

It looks like it's not much, but since it's been a short time after Java 12 release, it's not natural to expect some massive changes. Also, as you can see in Java SE Support Roadmap, this is one of the non-LTS versions, and releases between the Long-Term Support (LTS) versions are mostly there to show certain features as previews in order to get early feedback from users. Next to these five JDK Enhancement Proposals (JEPs), there are 76 new core library elements (most of them are additions to the java.io package).

Java 13 features marked as preview mean that they are still not included in relevant Java Language Specification. Users test and feedback will decide their destiny. To be able to use Java 13 features in preview mode, you need to enable them for both compilation and runtime explicitly. In case of compilation:

javac --enable-preview --release 13 FeatureClass.java

To run the application, you need to enable the preview Java 13 features you used in code:

java --enable-preview FeatureClass

Now, let's go through new Java 13 features.

Java 13 features

Dynamic CDS Archives - JEP 350

Class data sharing (CDS) has its roots in Java 5. The main purpose of CDS is to shorten the start times of Java applications by storing specific information concerning classes in Class Data Sharing archives. This data is then available to different JVMs. This feature is an extension to application data sharing functionality (AppCDS). It was commercial before it was contributed by Oracle to OpenJDK 10. This extension allows the dynamic archiving of classes at the end of the execution of a Java application.

Text Blocks - JEP 355 (Preview)

Java was always a little thin with a way strings are defined. A string starts and ends with a double-quote, which is ok, except that the String can not contain more than one line. If you wanted to have more than one line in resulting String, you would use "\n". Other languages such as Scala or Kotlin have the possibility of defining multi-line texts for a long time.

Java 13 features bring text blocks as another solution to the same issue. A text block starts and ends with a triple double-quote. Anything between is interpreted as a part of the String, including newlines. The result is regular java.lang.String object. Text blocks could be used the same as typical String with no difference to the compiled code except that it can not contain only one line since this will produce an error.

The positioning of the closing quotes is important since it determines how whitespaces are handled.

Switch Expressions - JEP 354 (Preview)

As text blocks, this feature is also in preview mode, as it was in Java 12. Java 13 extended it with some enhancements. So, how does switch look like in Java 13?

  • Now you yield value from a switch expression since the break with value statement is to be replaced with the yield statement.
  • One very useful change is that switch is extended so it can be used as either a statement or an expression.
  • Fall-throughs are elegantly solved with the option to use multiple labels in the same line which leads to easier to handle and less error-prone code.

So, in older Java versions switch statement looked like this:

public class HelloWorld{
 enum Month {
  JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER
}
     public static void main(String []args){
        System.out.println("Hello World");
        
        int numberOfDays;
 Month month = Month.JANUARY;
switch (month) { 
    case JANUARY: 
    case MARCH: 
    case MAY: 
    case JULY: 
    case AUGUST: 
    case OCTOBER: 
    case DECEMBER: { 
        numberOfDays = 31; 
        break; 
    } 
    case FEBRUARY: {
        numberOfDays = 28; 
        break;
    } 
    case APRIL: 
    case JUNE: 
    case SEPTEMBER: 
    case NOVEMBER: {
        numberOfDays = 30; 
        break; 
    } 
    default: throw new IllegalStateException("Unknown month: " + month); 
    }
     System.out.println(numberOfDays);
  }
}
    

With Java 13 features enabled this would look like:

int numberOfDays = switch (month) { 
case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER: yield 31; 
case FEBRUARY: yield 28; 
case APRIL, JUNE, SEPTEMBER, NOVEMBER: yield 30; 
default: throw new IllegalStateException("Unknown month: " + month); 
}

Or with use of arrow syntax introduced in Java 12:

int numberOfDays = switch (month) { 
case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER -> 31; 
case FEBRUARY -> 28; 
case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30; 
default -> throw new IllegalStateException("Unknown month: " + month); 
}

Reimplement the Legacy Socket API - JEP 353

A reimplementation of the legacy socket API replaces the existing implementation used by the net. Socket and java.net.ServerSocket APIs with an easier, more modern implementation. Legacy APIs date back to JDK 1.0 and comprise a mix of legacy C and Java code which is hard to debug and maintain. For example, the thread stack was used as the IO buffer. The legacy implementation also has other issues: a native data structure to support asynchronous close, causing reliability and porting issues, and concurrency issues requiring an overhaul.

JDK 13 brings better implementation, NioSocketImpl, which simplifies porting to multiple platforms. In the same time, it makes use of the existing buffer cache mechanism so the thread stack is not used for this purpose. It also uses java.util.concurrent locks rather than synchronized methods. This makes integration with fibres much easier. Fibres are part of project Loom, which represents an attempt by the OpenJDK community support a high-throughput, lightweight concurrency model in Java. It's still in development and is not integrated into JDK. Yet.

ZGC: Uncommit unused memory - JEP 351

ZGC is an experimental low-latency garbage collector, introduced in JDK 11.

The ZGC heap contains a set of heap regions called ZPages. When ZPages get empty during a GC cycle, they are returned to the ZPageCache. ZPages in this cache are placed by the least recently used order. In JDK 13, the ZGC will return pages marked as unused for a sufficiently long time interval to the operating system. This enables their reusability for other processes. Uncommitting memory will never cause the heap size to narrow below the minimum specified size. If both minimum and maximum heap sizes are the same, no memory will be uncommitted.