Java 17

created onOctober 4, 2022

general availability on 2021-09-14

JEPs

new features

JEP state summary /remark
JEP 306: Restore Always-Strict Floating-Point Semantics standard make floating-point operations consistently strict, rather than have both strict floating-point semantics (strictfp) and subtly different default floating-point semantics. This will restore the original floating-point semantics to the language and VM, matching the semantics before the introduction of strict and default floating-point modes in Java SE 1.2.
JEP 356: Enhanced Pseudo-Random Number Generators standard the new interface RandomGenerator supplies a uniform API for all existing and new PRNGs. RandomGenerators provide methods named ints, longs, doubles, nextBoolean, nextInt, nextLong, nextDouble, and nextFloat, with all their current parameter variations.
JEP 403: Strongly Encapsulate JDK Internals standard Code successfully compiled with earlier releases that directly accesses internal APIs of the JDK will no longer work by default. The strong encapsulation, which has been the default since JDK 9 can be relaxed with the JVM option –illegal-access. The sun.misc package will still be exported by the jdk.unsupported module, and will still be accessible via reflection. Hacking open private fields and protected or private methods of exported java.* APIs by reflection will result in an java.lang.reflect.InaccessibleObjectException. see comment on JEP 396: Strongly Encapsulate JDK Internals by Default.
JEP 406: Pattern Matching for switch preview introduces pattern matching for switch expressions and statements, along with extensions to the language of patterns.
JEP 409: Sealed Classes standard allows the author of a class to specify which classes may extend the class. This allows for more fine grained control of inheritance hierarchies. See comments on JEP 360: Sealed Classes (Preview).
JEP 412: Foreign Function & Memory API incubator eases the acces for devs to code and data on the same machine as the JVM but outside of the JVM, without the drawbacks of JNI.
JEP 414: Vector API second incubator provides a second iteration of an incubator module, jdk.incubator.vector, to express vector computations that reliably compile at runtime to optimal vector hardware instructions on supported CPU architectures and thus achieve superior performance to equivalent scalar computations.
JEP 415: Context-Specific Deserialization Filters standard allows applications to configure context-specific and dynamically-selected deserialization filters via a JVM-wide filter factory that is invoked to select a filter for each individual deserialization operation. This JEP addresses some drawbacks of the deserialization filters introduced in Java 9 with JEP 290: Filter Incoming Serialization Data .

JDK internal

JEP summary /remark
JEP 382: New macOS Rendering Pipeline implement a Java 2D internal rendering pipeline for macOS using the Apple Metal API as alternative to the existing pipeline, which uses the deprecated Apple OpenGL API.
JEP 391: macOS/AArch64 Port port the JDK to macOS/AArch64. Apple has announced a long-term plan to transition their line of Macintosh computers from x64 to AArch64.

deprecated

JEP summary /remark
JEP 398: Deprecate the Applet API for Removal deprecate the Applet API for removal. The Applet API was previously deprecated, though not for removal, by JEP 289: Deprecate the Applet API in Java 9.
JEP 411: Deprecate the Security Manager for Removal deprecates the Security Manager for removal in a future release. The Security Manager dates from Java 1.0. It has not been the primary means of securing client-side Java code for many years, and it has rarely been used to secure server-side code.

removed

JEP summary /remark
JEP 407: Remove RMI Activation removes the Remote Method Invocation (RMI) Activation mechanism, while preserving the rest of RMI. The Jakarta Activation (JavaBeans Activation Framework / JAF in Java EE) is completely unrelated to the Java SE Remote Method Invocation (RMI) Activation and thus not affected by the removal.
JEP 410: Remove the Experimental AOT and JIT Compiler remove the experimental Java-based ahead-of-time (AOT) and just-in-time (JIT) compiler. This compiler has seen little use since its introduction and the effort required to maintain it is significant. Devs who want to use the Graal compiler for either AOT or JIT compilation can use the Graal VM

some feature details

JEP 356: Enhanced Pseudo-Random Number Generators

Four new specialized random generator interfaces that extend RandomGenerator are provided:

  • SplittableRandomGenerator provides the methods split and splits, that allows an user to spawn a new RandomGenerator from an existing RandomGenerator that will generally produce statistically independent results.
  • JumpableRandomGenerator, provides the methods jump and jumps. Jumpability allows a user to jump ahead a moderate number of draws.
  • LeapableRandomGenerator, provides methods named leap and leaps. Leapability allows a user to jump ahead a large number of draws.
  • ArbitrarilyJumpableRandomGenerator, provides additional variations of jump and jumps that allow an arbitrary jump distance to be specified.

JEP 406: Pattern Matching for switch (Preview)

the familiar instanceof-and-cast idiom:

if (o instanceof String) { String s = (String)o; System.out.println(s); }

can now be simplified to:

if (o instanceof String s) { System.out.println(s); }

pattern matching and null

Traditionally, switch statements and expressions throw NullPointerException if the selector expression evaluates to null, so testing for null must be done outside of the switch:

static void check(String s) { if (s == null) { System.out.println("oops!"); return; } switch (s) { case "apple", "banana" -> System.out.println("Great"); default -> System.out.println("Ok"); } }

This has been relaxed by introducing a new null label for a case, that matches when the value of the selector expression is null. The code above can thus be written in a more concise form:

static void check(String s) { switch (s) { case null -> System.out.println("oops!"); case "apple", "banana" -> System.out.println("Great"); default -> System.out.println("Ok"); } }
Both switch expressions and pattern switch statements must be exhaustive. The switch block must deal with all possible values of the selector expression.

guarded patterns

A new kind of pattern called a guarded pattern, written p && b, that allows a pattern p to be refined by an arbitrary boolean expression b, i.e.:

static void testTriangle(Shape s) { switch (s) { case Triangle t && (t.calculateArea() > 100) -> System.out.println(“Large triangle”); default -> System.out.println(“A shape, possibly a small triangle”); } }

dominance of pattern labels, total type patterns and match-all labels.

in the following switch statement:

static void check(Object o) { switch(o) { case CharSequence cs -> System.out.println(“a sequence of length " + cs.length()"); case String s -> System.out.println(“A string: " + s); // Error - pattern is dominated by previous pattern default -> { break; } } }

the first pattern label case CharSequence cs dominates the second pattern label case String s because every value that matches the pattern String s also matches the pattern CharSequence cs, but not vice versa, because String is a subtype of CharSequence.

A type pattern p of type U is total for a type T, if T is a subtype of U. For example, the type pattern CharSequence and Object are total for the type String. In the code above, CharSequence cs is a total type pattern.

The two match-all labels are default and total type patterns.

It is also a compile-time error if a switch block has more than one match-all switch label.

scope of pattern variable declarations

In the code below, the declaration of s is in scope in the right-hand operand of the && expression, as well as in the “then” block. However, it is not in scope in the “else” block; If the “else” block is invoked, the pattern match must fail, because the pattern variable will not have been initialized:

static void check(Object o) { if ((o instanceof String s) && s.length() > 3) { System.out.println(s); } else { System.out.println(s + "is not a string"); // error } }

This has been relaxed for switch statements. In the code below, the scope of the declaration of the pattern variable s is the block to the right of the first arrow.

static void check(Object o) { switch (o) { case String s -> { if (s.equalsIgnoreCase( "Apple" )) { System.out.println(s + " is fine"); } System.out.println(s); } case Integer i -> throw new IllegalStateException("Invalid Integer argument of value " + i.intValue()); default -> { break; } } }

The scope of a pattern variable declaration is defined as:

" 1. The scope of a pattern variable declaration which occurs in a case label of a switch rule includes the expression, block, or throw statement that appears to the right of the arrow.
2. The scope of a pattern variable declaration which occurs in a case label of a switch labeled statement group, where there are no further switch labels that follow, includes the block statements of the statement group. "
JEP 406: Pattern Matching for switch (Preview), section 3, Scope of pattern variable declarations
Allowing execution to fall through a case label that declares a pattern variable results in a compile-time error.

Consider the following code:

static void check(Object o) { switch (o) { case String s: { if (s.equalsIgnoreCase( "Apple" )) { System.out.println(s + " is fine"); } System.out.println(s); } case Integer i: throw new IllegalStateException("Invalid Integer argument of value " + i.intValue()); default -> { break; } } }

If this were allowed and the value of the selector expression o was a String, then execution of the switch block could fall through the second statement group (after case Integer i:) where the pattern variable i would not have been initialized.

The same problem arises with multiple patterns in a case label. Consider a case label like:

static void check(Object o) switch(Object o){ case String s, Integer i->{ // some code } }

In this case, both s and i would be in scope after the arrow, yet only one of s and i would have been initialized depending on whether the value of o was a String or an Integer. The same applies to fall-through labels.

Multiple patterns in a case label result in a compile time error

JEP 411: Deprecate the Security Manager for Removal

The Security Manager dates from Java 1.0. In the era of applets, which are dead now, the SecurityManager protected the integrity of users' machines and the confidentiality of their data by running applets in a sandbox, which denied access to resources such as the file system or the network.

The other area of application of the SecurityManager, namely guarding againts the threat of accidental vulnerabilities in local code is almost impossible to address with the Security Manager, especially when considering the class libraries of nowadays JDK versions compared to the class libraries of JDK 1.0. The main problems here are the brittle permission model, the difficult programming model and the poor performance of the SecurityManager. It is used far less in production than many people assume.

reference

OpenJDK JDK 17 Feature List and Schedule

JEP 356: Enhanced Pseudo-Random Number Generators

JEP 406: Pattern Matching for switch (Preview)

JEP 411: Deprecate the Security Manager for Removal