Get Your Copy of The CXO's Playbook for Gen AI: Practical Insights From Industry Leaders.  Download Now >
Back to Blogs

Java 17 New Features: Here's a Juicy Update in JDK17

With the recent release of the Java 17 LTS release, many new language features have been added to JDK. Let’s explore each of these new features in JDK17 in brief.

List of JEPs

JEP 306: Restore Always-Strict Floating-Point Semantics

This JEP is focused on scientific applications and aims to enforce strict floating-point operations across all platforms. It ensures consistent results from floating-point calculations by using strict or strictfp modes, which guarantee uniformity in computations regardless of the underlying hardware.

JEP 356: Enhanced Pseudo-Random Number Generators

JEP 356 introduces enhancements for Pseudo-Random Number Generators (PRNGs), catering to specialized use cases. It provides new interfaces and implementations that make it simpler to switch between different PRNG algorithms. Additionally, it improves support for stream-based programming.

JEP 378: Text Blocks

Multi-line String literals can be represented in quotes without having to deal with most escape sequences.

Consider the below example of populating an HTML string in a string variable, before text blocks. We need to escape with new line escapes and concatenation for the below multiple line spanning string, manually processing the below string can be error-prone.

String html = "<html>n" +
      "<body>n"+
      "<p>Test</p>n"+
      "</body>n"+
      "</html>n";

With a text block in JDK17, the above string can be rewritten with a text block like below, it is defined with three double quotes and it can span in multiple lines. The text block automatically formats the strings in a predictable way and gives the developer control over the format needed.

String html = """
<html>
<body>
<p>Test</p>
</body>
</html>
      """;

JEP 382: New macOS Rendering Pipeline

This JEP introduces a new Java 2D internal rendering pipeline for macOS, replacing the deprecated OpenGL API (which was phased out in macOS 10.14) previously used in Swing GUI applications. The updated pipeline utilizes the Apple Metal API, ensuring continued support for macOS while maintaining compatibility with existing APIs. This transition allows for improved performance and modern graphics support without altering the public API surface.

JEP 391: macOS/AArch64 Port 

Apple has announced a long-term transition of its computer line from x64 architecture to AArch64. This JEP facilitates the porting of the JDK to run on AArch64 architecture for macOS platforms, ensuring that Java applications remain compatible and performant as Apple shifts its hardware to the new architecture.

JEP 394: Pattern Matching for instanceof

Pattern matching allows the conditional extraction of components from objects to be expressed more concisely and safely.

Let's consider the below example, here we are first testing whether obj is a string, then the declaration of string variables, and then type casting obj to a string into variables.

if(obj instanceof String) {
      String s = (String) obj;
}

With JDK17, pattern matching for the instance feature, we can reduce the code to a single line like below, i.e, the variable s is created only when obj is an instance of String, and type casting obj to string happens automatically.

if(obj instanceof String s) {
      //use s
} else {
      // s is out of scope here
}

JEP 395: Pattern Matching for instanceof

Records provide a compact syntax for declaring classes that are transparent holders for shallowly immutable data.

JDK 16 had a records feature, for developers who needed to deal with boilerplate codes (such as getter/setter, constructor, equals, and hashcode implementations).

Records are built on components, components are compiled as final fields, like below, they are the only fields that can have records, but we cannot add any instance fields to records.

record range(int start, int end){}

Record is a final class, no state can be added to the record class through inheritance.

public final class point{
final int x;
final int y;
}

Previously, in JDK 16, the final class would have been written using the below approach.

public final class point{
  final int x;
  final int y;

  public point(int x, int y) {
      this.x = x;
      this.y = y;
  }

  @Override
  public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      point point = (point) o;
      return x == point.x && y == point.y;
  }

  @Override
  public int hashCode() {
      return Objects.hash(x, y);
  }

  @Override
  public String toString() {
      return "point{" +
              "x=" + x +
              ", y=" + y +
              '}';
  }

  public int x(){
      return x;
  }

  public int y(){
      return y;
  }
}

JEP 398: Deprecate the Applet API for Removal

For many Java developers who began their careers using Applet APIs, this change may be a disappointment. However, as most web browsers have already phased out support for Java plugins, the Applet API has increasingly become obsolete. This version officially marks its removal, following its deprecation since Java 9.

JEP 403: Strongly Encapsulate JDK Internals

JEP 403 takes a significant step towards enhancing the encapsulation of JDK internals by removing the –illegal-access flag. This flag, which previously allowed access to internal APIs, will now be ignored by the platform. If the flag is used, the console will display a message indicating its discontinuation. This change aims to prevent JDK users from accessing internal APIs, with the notable exception of critical ones like sun.misc.Unsafe.

JEP 406: Pattern Matching for switch (Preview)

‍Pattern matching on the switch allows an expression to be tested against a number of patterns, each with a specific action.

  • allow patterns to appear in case labels
  • introduces case null statement

Current switch statements allow working on a few types: numeric, enum, and string. If we want to use patterns to check for certain conditions, then the chain of if-else condition blocks is used as shown below.

static String formatter(Object o){
  String formatted = "unknown";
  if(o instanceof Integer i){
      formatted = String.format("int %d",i);
  } else if ( o instanceof Long l){
      formatted = String.format("long %d",l);
  }
  return formatted;
}

With the new feature “pattern matching for switch”, a chain of if-else conditions is replaced with switch expressions as it checks for the pattern.

static String formatter(Object o){
  return switch(o){
      case null      -> "null";
      case Integer i -> String.format("int %d", i);
      case Long l    -> String.format("long %d", l);
      default        -> o.toString();
  };
}

JEP 407: Remove RMI Activation

Scheduled for removal in JDK 15, this JEP officially eliminates the RMI Activation API from the platform in JDK 17.

JEP 409: Sealed Classes

‍Added as a preview in JDK16, sealed classes and interfaces restrict which other classes need to implement or extend them. It allows the author of the class or interfaces to control which code is responsible for extending or implementing them.

  • Provides a more declarative way than access modifiers to restrict the use of superclass.
  • Support future enhancements in pattern matching to avoid exhaustive analysis of patterns.

A class is sealed by adding a sealed modifier to its declaration, and the permits clause specifies classes that are permitted to extend a sealed class, sealed class and a permitted subclass need to be in the same module. If the module is not defined, it needs to be in the same package. Subclasses extending sealed classes can be either final, another sealed class, or non-sealed classes, like in the below example.

package com.domain.shapes;

public abstract sealed class Shape permits Circle,Square, Rectangle {

}

public final class Circle extends Shape {

}

public non-sealed class Square extends Shape {

}

public sealed class Rectangle extends Shape permits TransparentRectange,OpaqueRectangle {

}

public final class OpaqueRectangle extends Rectangle {

}

public final class TransparentRectange extends Rectangle {

}

JEP 410: Remove the Experimental AOT and JIT Compiler

Introduced as experimental features in JDK 9 and JDK 10, respectively, Ahead-Of-Time (AOT) compilation (JEP 295) and the GraalVM Just-In-Time (JIT) compiler (JEP 317) faced high maintenance costs without achieving widespread adoption. Due to their limited use and the complexity involved in maintaining these features, this JEP has decided to remove them from the core platform. However, developers interested in these capabilities can still utilize them through GraalVM, which continues to support both AOT and JIT compilation, providing an alternative for those who need these advanced features.

JEP 411: Deprecate the Security Manager for Removal

The security manager, originally designed to secure client-side Java applications, has been marked for removal due to its diminishing relevance. As the security landscape has evolved, this feature has become less applicable and is no longer necessary for modern Java applications.

JEP 412: Foreign Function & Memory API (Incubator)

The Foreign Function and Memory API enables Java developers to interact with code outside the JVM and manage memory beyond the heap. Designed to replace the legacy JNI API, this new API enhances both security and performance.

Developed under Project Panama, the Foreign Function and Memory API has been refined through JEPs 393, 389, 383, and 370. It facilitates direct calls to C libraries from Java classes, streamlining integration with native code and optimizing resource management.

JEP 414: Vector API (Second Incubator)

The Vector API introduces support for SIMD (Single Instruction, Multiple Data) operations, which execute multiple sets of instructions simultaneously. By utilizing specialized CPU hardware that supports vector instructions, the API enables efficient parallel processing, allowing operations to be executed as pipelines.

This new API empowers developers to write more optimized code that harnesses the full capabilities of modern hardware. Typical applications benefiting from this API include scientific computing, image processing, text manipulation, and any task involving complex arithmetic or operations on multiple independent data elements.

JEP 415: Context-Specific Deserialization Filters

Introduced in JDK 9, JEP 290 brought crucial enhancements to the validation of serialized data from untrusted sources, addressing significant security risks. This validation is performed at the JVM level, offering enhanced security and robustness.

Building on this, JEP 415 expands the capability by allowing applications to configure deserialization filters that are both context-specific and dynamically selected. These filters are defined at the JVM level and are applied during each deserialization operation, further strengthening data integrity and security.

Sealed Classes — JDK 17 JEP 409

Added as a preview in JDK16, sealed classes and interfaces restrict which other classes need to implement or extend them. It allows the author of the class or interfaces to control which code is responsible for extending or implementing them.

  • Provides a more declarative way than access modifiers to restrict the use of superclass.
  • Support future enhancements in pattern matching to avoid exhaustive analysis of patterns.

A class is sealed by adding a sealed modifier to its declaration, and the permits clause specifies classes that are permitted to extend a sealed class, sealed class and a permitted subclass need to be in the same module. If the module is not defined, it needs to be in the same package. Subclasses extending sealed classes can be either final, another sealed class, or non-sealed classes, like in the below example.

package com.domain.shapes;

public abstract sealed class Shape permits Circle,Square, Rectangle {
}

public final class Circle extends Shape {
}

public non-sealed class Square extends Shape {
}

public sealed class Rectangle extends Shape permits TransparentRectange,OpaqueRectangle {
}

public final class OpaqueRectangle extends Rectangle {
}

public final class TransparentRectange extends Rectangle {
}

Text Blocks — JDK 17 JEP 378

Multi-line String literals can be represented in quotes without having to deal with most escape sequences.

Consider the below example of populating an HTML string in a string variable, before text blocks. We need to escape with new line escapes and concatenation for the below multiple line spanning string, manually processing the below string can be error-prone.

String html = "<html>n" +
       "<body>n"+
       "<p>Test</p>n"+
       "</body>n"+
       "</html>n";

With a text block in JDK17, the above string can be rewritten with a text block like below, it is defined with three double quotes and it can span in multiple lines. The text block automatically formats the strings in a predictable way and gives the developer control over the format needed.

String html = """
<html>
<body>
<p>Test</p>
</body>
</html>
       """;

Pattern Matching for instanceof — JDK 16 JEP 394

Pattern matching allows the conditional extraction of components from objects to be expressed more concisely and safely.

Let's consider the below example, here we are first testing whether obj is a string, then the declaration of string variables, and then type casting obj to a string into variables.

if(obj instanceof String) {
       String s = (String) obj;
}

With JDK17, pattern matching for the instance feature, we can reduce the code to a single line like below, i.e, the variable s is created only when obj is an instance of String, and type casting obj to string happens automatically.

if(obj instanceof String s) {
       //use s
} else {
       // s is out of scope here
}

Switch Expressions (JDK 14 JEP 361)

This extends the switch, so it can be used as a switch statement or expression. Both forms can be used.

raditional case ... : labels //with fall through
New        case ... -> labels //without fall through

New statement “yield” has been added for yielding (Returning) a value from switch expression.

For example, with the traditional switch expression in Java.

int  numLetters;
switch(day)
 {
     case MONDAY:
     case FRIDAY:
     case SUNDAY:
         numLetters = 6;
         break;
     case TUESDAY:
         numLetters = 7;
         break;
     case THURSDAY:
     case SATURDAY:
         numLetters = 8;
     case WEDNESDAY:
         numLetters = 9;
         break;
     default:
         throw new IllegalArgumentException(" Not a day: " + day);
 }
 return numLetters;

Using switch expressions, it returns a value. No extra variables are needed as in the above case, and multiple constants are separated by a comma and can be defined in each branch.

return switch(day) {
   case   MONDAY, FRIDAY, SUNDAY -> 6;
   case   TUESDAY -> 7;
   case   THURSDAY, SATURDAY -> 8;
   case   WEDNESDAY -> 9;
  }

Pattern Matching for switch Preview — JDK 17 JEP 406

Pattern matching on the switch allows an expression to be tested against a number of patterns, each with a specific action.

  • allow patterns to appear in case labels
  • introduces case null statement

Current switch statements allow working on a few types: numeric, enum, and string. If we want to use patterns to check for certain conditions, then the chain of if-else condition blocks is used as shown below.

static String formatter(Object o){
   String formatted = "unknown";
   if(o instanceof Integer i){
       formatted = String.format("int %d",i);
   } else if ( o instanceof Long l){
       formatted = String.format("long %d",l);
   }
   return formatted;
}

With the new feature “pattern matching for switch”, a chain of if-else conditions is replaced with switch expressions as it checks for the pattern.

static String formatter(Object o){
   return switch(o){
       case null      -> "null";
       case Integer i -> String.format("int %d", i);
       case Long l    -> String.format("long %d", l);
       default        -> o.toString();
   };
}

Records — JDK 16 JEP 395

Records provide a compact syntax for declaring classes that are transparent holders for shallowly immutable data.

JDK 16 had a records feature, for developers who needed to deal with boilerplate codes (such as getter/setter, constructor, equals, and hashcode implementations).

Records are built on components, components are compiled as final fields, like below, they are the only fields that can have records, but we cannot add any instance fields to records.

record range(int start, int end){}

Record is a final class, no state can be added to the record class through inheritance.

public final class point{
final int x;
final int y;
}

Previously, in JDK 16, the final class would have been written using the below approach.

public final class point{
   final int x;
   final int y;

   public point(int x, int y) {
       this.x = x;
       this.y = y;
   }

   @Override
   public boolean equals(Object o) {
       if (this == o) return true;
       if (o == null || getClass() != o.getClass()) return false;
       point point = (point) o;
       return x == point.x && y == point.y;
   }

   @Override
   public int hashCode() {
       return Objects.hash(x, y);
   }

   @Override
   public String toString() {
       return "point{" +
               "x=" + x +
               ", y=" + y +
               '}';
   }

   public int x(){
       return x;
   }

   public int y(){
       return y;
   }
}

With JDK17, instead of class, we say records, so that the compiler can make sure our records will get all required methods without having to explicitly define them. Records are not just eliminating boilerplate codes. Records represent improvements in the platform.

By embracing Java 17, developers can leverage its improvements to create more efficient, maintainable, and scalable applications. Whether you’re migrating existing projects or starting new ones, now is the perfect time to explore the capabilities of Java 17. 

As the Java ecosystem continues to evolve, staying updated with the latest versions will ensure that you harness the full potential of this powerful language in your software development endeavors. Whether you're looking to upgrade existing applications or start new projects, leveraging the latest enhancements will set you up for success. 

Check out our custom application development services to learn about why Ideas2IT will be the right choice for all your application development related needs.

Ideas2IT Team

Connect with Us

We'd love to brainstorm your priority tech initiatives and contribute to the best outcomes.