Features in Java 17 (JDK 17)

Mutlu OKUDUCU
9 min readJan 23, 2023

--

Mutlu Okuducu/ Software Developer

Programmers typically target a specific, long-term support (LTS) release when they develop applications. That means for the past several years, most Java developers were limited to the Java 8 or Java 11 feature set.

The newest long-term support release for the Java SE platform is Java 17 LTS. Under the Oracle No-Fee Terms and Conditions License, JDK 17 binaries are free to use in production and redistribute at no cost. LTS stands for long-term support. It will be available on September 15, 2021.

Several improvements in these Java 17 features will make enterprise software development much easier.

  • Spring Boot 3.0 is now generally available. The new release is based on Spring Framework 6.0 and requires Java 17.

Top 5 Java 17 features that developers will love.

  1. The new Java Record data type (JDK 14)
  2. Java text blocks (JDK 14)
  3. Helpful NullPointerException guidance (JDK 14)
  4. Pattern Matching for Switch (Preview)
  5. Sealed classes
  6. Enhanced Pseudo-Random Number Generator

1- The new Java Record data type;

Records:

Records focus on certain domain classes whose purpose is only to store data in fields. A new class called record is a final class, not abstract, and all of its fields are final as well. The record will automatically generate the constructors, getters, equals(), hashCode()and toString() during compile-time and it can implements interfaces.

Restrictions:

  • A record is a final class
  • A record cannot extend a class
  • The value (reference) of a field is final and cannot be changed
  • A record class is an immutable
  • A record can not setters
public record Transaction(int id, double amount, String description {
}
/*
---- * You can use JShell with the flag --enable-preview

Automatically generate:
* constructors
* getters
* equals()
* hashCode()
* toString()
*/

//You can use Transaction like any regular class:

Transaction trans = new Transaction(5, 100, "Payment");
int amount= trans.amount();
int description= trans.description();

You can find the code, records.

2- Java text blocks;

In Java, embedding HTML, XML, SQL, TEXT BLOCK or JSON snippets into code is often hard to read and hard to keep, and to overcome this problem, Java 14 has introduced Text Block. A text block contains zero or more content characters enclosed by open and closed delimiters.

The text block starts and ends with three quotation marks each. The following rules apply:

  • Text block using three double-quote characters
  • newlines (line-terminator) denoted by \
  • for white space (single space) denoted by /s
  • string format for a parameter using %s
  • You do not need to escape single or double quotes within the text block, but you may (though SCA tools such as SonarLint recommend not doing so).
String text = """"""; // illegal text block start
String text = """ """; // illegal text block start

String text = """
"""; // legal text block

// Text block//Without Text Block HTML
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
System.out.println(html);

// Text Block HTML
String htmlTag = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";

// Text Block multi line (paragraph)
String text = """
two escape sequences first is for newlines \
and, second is to signify white space \
or single space.\
""";
// Text Block SQL Query
String query1 = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";

// Text Block JSON Example
String json= """
{
"amount": {
"currency": "string",
"value": 0
},
"creditorAccount": {
"accountName": "string",
"accountNumber": "string",
"sortCode": "string"
},
"debtorAccount": {
"accountName": "string",
"accountNumber": "string",
"sortCode": "string"
},
"paymentDate": "string",
"reference": "string"
}
""";

The following examples are string formatted.

String html1 = """ 
<html>
<body>
<p>%s, %s</p>
</body>
</html>
""";

String print = html1.formatted("Hello1", "Java 14");

String html2 =
String.format("""
<html>
<body>
<p>%s, %s</p>
</body>
</html>
""", "Hello2", "Java 14");

String html3 = """
<html>
<body>
<p>%s, %s</p>
</body>
</html>
""".formatted("Hello3", "Java 14");

You can find the code, textsblocks.

3- Helpful NullPointerException guidance;

NullPointerExceptions cause frustrations because they often appear in application logs when code is running in a production environment, which can make debugging difficult. After all, the original code is not readily available. For example, consider the code below:

Account account =new Account();
String accountNumber=account.getAmount().getCurrency(); //line 15
System.out.println(accountNumber.length());

Before Java 14, you might get the following error:

Exception in thread

“main” java.lang.NullPointerException
com.java14features.nullpointerexception.Example1.main(Example1.java:15)

Unfortunately, if at line 15, there’s an assignment with multiple method invocations getAmount() and getCurrency() either one could be returning null. So, it’s not clear what is causing the NullPointerException

Now, with Java 17, there’s a new JVM feature through which you can receive more-informative diagnostics:

Exception in thread “main” java.lang.NullPointerException: Cannot invoke “com.java14features.dto.Amount.getCurrency()” because the return value of “com.java14features.dto.Account.getAmount()” is null at com.java14features.nullpointerexception.Example1.main(Example1.java:16)

The message now has two clear components:

The consequence: Amount.getCurrency() cannot be invoked.

The reason: The return value of Account.getAmount() is null.

The enhanced diagnostics work only when you run Java with the following flag: -XX:+ShowCodeDetailsInExceptionMessages

You can find the code, null pointer exception.

4- Pattern Matching for Switch (Preview):

The Switch Expressions were released in Java 14, and it becomes a standard language feature, we can use these Switch Expressions which can be used as an expression with help of an arrow (->), and now can yield/return the value.

Switch Expressions are actually two enhancements that can be used independently but also combined:

  1. Arrow notation without break and fall-throughs
  2. Using switch as an expression with a return value
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println((int) Math.pow(2, 3));
case WEDNESDAY -> {
int three = 1 + 2;
System.out.println(three * three);
}
}

The following examples call the method and return a new yield.

public static void main(String[] args) {  
for (VehicleType vehicle : VehicleType.values()) {
int speedLimit = getSpeedLimit(vehicle);
System.out.println("Speed limit: " + vehicle + ":" + speedLimit);
}
}

private static int getSpeedLimit(VehicleType vehicleType) {
return switch (vehicleType) {
case BIKE, SCOOTER -> 40;
case MOTORBIKE, AUTOMOBILE -> 140;
case TRUCK -> 80;
};
}


public static void main(String[] args) {
Days day = FRIDAY;
int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int result = day.toString().length();
yield result;
}
};
System.out.println(j);
}
}

Pattern matching and null

Now we can test the null in switch directly.

Old code.

public static void main(String[] args) {

testString("Java 16"); // Ok
testString("Java 11"); // LTS
testString(""); // Ok
testString(null); // Unknown!
}

static void testString(String s) {
if (s == null) {
System.out.println("Unknown!");
return;
}
switch (s) {
case "Java 11", "Java 17" -> System.out.println("LTS");
default -> System.out.println("Ok");
}
}

After JDK 17

public static void main(String[] args) {

testStringJava17("Java 16"); // Ok
testStringJava17("Java 11"); // LTS
testStringJava17(""); // Ok
testStringJava17(null); // Unknown!
}

static void testStringJava17(String s) {
switch (s) {
case null -> System.out.println("Unknown!");
case "Java 11", "Java 17" -> System.out.println("LTS");
default -> System.out.println("Ok");
}
}

Further Reading

JEP 406: Pattern Matching for switch (Preview)

You can find the code, switches.

5- Sealed classes:

Sealed classes and interfaces were the big news in Java 17.

Inheritance is a powerful construct. But there are very few Java syntax checkpoints that limit the potential for inheritance-based, object-oriented corruption. The sealed Java class helps reign in the overzealous and often detrimental abuse of Java inheritance.

Sealed classes allow a developer to explicitly declare the names of the components that can legally inherit from a class they create. No longer is the inelegant use of an access modifier the only way to restrict the use of a superclass.

In this section, you will learn:

  • What are sealed classes and interfaces?
  • How exactly do sealed classes and interfaces work?
  • What do we need them for?
  • Why should we restrict the extensibility of a class hierarchy?
The syntax for a sealed base class and its derived classes. URL: https://blogs.oracle.com/javamagazine/post/java-sealed-classes-fight-ambiguity
From: https://blogs.oracle.com/javamagazine/post/java-sealed-classes-fight-ambiguity

Let’s start with an example…

  • Sealed classes are declared using sealed modifier and permits clause. permits clause specifies the sub-classes which can extend the current sealed class.
 
sealed class SuperClass permits SubClassOne, SubClassTwo
{
//Sealed Super Class
}

final class SubClassOne extends SuperClass
{
//Final Sub Class
}

final class SubClassTwo extends SuperClass
{
//Final Sub Class
}
  • Permitted sub-classes must be either final or sealed or non-sealed. If you don’t declare permitted sub-classes with any one of these modifiers, you will get compile time error.
sealed class SuperClass permits SubClassOne, SubClassTwo, SubClassThree
{
//Sealed Super Class
}

final class SubClassOne extends SuperClass
{
//Final Sub Class
}

sealed class SubClassTwo extends SuperClass permits AnotherSubClass
{
//Sealed Sub Class permitting another subclass to extend it further
}

non-sealed class SubClassThree extends SuperClass
{
//non-sealed subclass
}

final class AnotherSubClass extends SubClassTwo
{
//Final subclass of SubClassTwo
}
  • final permitted sub-classes can not be extended further, sealed permitted sub-classes are extended further by only permitted sub-classes and non-sealed permitted sub-classes can be extended by anyone.
  • Sealed class must and should specify its permitted subclasses using permits clause otherwise there will be a compilation error.
sealed class AnyClass 
{
//Compile Time Error: Sealed class must specify permitted subclasses
}
  • Permitted sub-classes must and should extend their sealed superclass directly.
sealed class Vehicle permits SubClassOne, SubClassTwo
{
//Sealed Super Class
}

final class SubClassOne
{
//Compile Time Error: It must extend SuperClass
}

non-sealed class SubClassTwo
{
//Compile Time Error: It must extend SuperClass
}
  • In the same way, you can also declare sealed interfaces with permitted sub interfaces or sub classes.
sealed interface SealedInterface permits SubInterface, SubClass
{
//Sealed Super Interface
}

non-sealed interface SubInterface extends SealedInterface
{
//Non-sealed Sub Interface
}

non-sealed class SubClass implements SealedInterface
{
//Non-sealed subclass
}
  • Permitted subinterfaces must be either sealed or non-sealed but not final.
sealed interface SealedInterface permits SubInterfaceOne, SubInterfaceTwo, SubInterfaceThree
{
//Sealed Super Interface
}

sealed interface SubInterfaceOne extends SealedInterface permits SubClass
{
//Sealed Sub Interface
}

non-sealed class SubClass implements SubInterfaceOne
{
//non-sealed subclass implementing SubInterfaceOne
}

non-sealed interface SubInterfaceTwo extends SealedInterface
{
//Non-sealed Sub Interface
}

final interface SubInterfaceThree extends SealedInterface
{
//Compile time Error: Permitted subinterface must not be final
}
  • Permitted sub types must have name. Hence, anonymous inner classes or local inner classes can’t be permitted sub types.
  • A sealed super class can be abstract, and permitted sub classes can also be abstract provided they can be either sealed or non-sealed but not final.
abstract sealed class SuperClass permits SubClassOne, SubClassTwo, SubClassThree
{
//Super class can be abstract and Sealed
}

abstract final class SubClassOne extends SuperClass
{
//Compile Time Error : Sub class can't be final and abstract
}

abstract non-sealed class SubClassTwo extends SuperClass
{
//Sub class can be abstract and Non-sealed
}

abstract sealed class SubClassThree extends SuperClass permits AnotherSubClass
{
//Sub class can be abstract and Sealed
}

final class AnotherSubClass extends SubClassThree
{
//Final sub class of SubClassThree
}
  • While declaring sealed classes and sealed interfaces, permits clause must be used after extends and implements clause.
  • With the introduction of sealed classes, two more methods are added to java.lang.Class (Reflection API). They are getPermittedSubclasses() and isSealed().

Also Read :

6- Enhanced Pseudo-Random Number Generators:

This JEP introduced a new interface called RandomGenerator to make future pseudorandom number generator (PRNG) algorithms easier to implement or use.

RandomNumberGenerator.java

package java.util.random;

public interface RandomNumberGenerator {
//...
}

The below example uses the new Java 17 RandomGeneratorFactory to get the famous Xoshiro256PlusPlus PRNG algorithms to generate random integers within a specific range, 0 – 5.

import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;

public class RandomNumberGenerator {

public static void main(String[] args) {

// legacy
// RandomGeneratorFactory.of("Random").create(42);

// default L32X64MixRandom
// RandomGenerator randomGenerator =
// RandomGeneratorFactory.getDefault().create();

RandomGenerator randomGenerator =
RandomGeneratorFactory.of("Xoshiro256PlusPlus").create(999);

System.out.println(randomGenerator.getClass());

int counter = 0;
while(counter<=5){
// 0-5
int result = randomGenerator.nextInt(6);
System.out.println(result);
counter++;
}
}
}

Output:

class jdk.random.Xoshiro256PlusPlus
4
6
9
5
7
6

All the Java 17 PRNG algorithms.

Group ---- Name
-------------------------
LXM : L128X1024MixRandom
LXM : L128X128MixRandom
LXM : L128X256MixRandom
LXM : L32X64MixRandom
LXM : L64X1024MixRandom
LXM : L64X128MixRandom
LXM : L64X128StarStarRandom
LXM : L64X256MixRandom
Legacy : Random
Legacy : SecureRandom
Legacy : SplittableRandom
Xoroshiro : Xoroshiro128PlusPlus
Xoshiro : Xoshiro256PlusPlus

Java 17 also refactored the legacy random classes like java.util.Random, SplittableRandom and SecureRandom to extend the new RandomGenerator interface.

Further Reading

JEP 356: Enhanced Pseudo-Random Number Generators

Java 17’s Enhanced Pseudo-Random Number Generators

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Mutlu OKUDUCU
Mutlu OKUDUCU

No responses yet

Write a response