Java 17 LTS Features
Java 17, released in September 2021, is the second long-term support (LTS) release after Java 11 and one of the most feature-rich Java versions in years. It finalizes several features that were in preview — records, sealed classes, pattern matching, and text blocks — making them officially production-ready.
Note: Java 17 also removes or deprecates a number of older APIs (including the Security Manager and RMI Activation). If you are migrating from Java 11, check the migration guide for removals.
Records (Finalized in Java 16, Stable in 17)
Records are immutable data classes that eliminate the constructor/getter/equals/hashCode/toString boilerplate you normally write by hand.
public record Point(int x, int y) {}
public class RecordsDemo {
public static void main(String[] args) {
Point p = new Point(3, 7);
System.out.println(p.x()); // accessor
System.out.println(p.y());
System.out.println(p); // toString()
System.out.println(p.equals(new Point(3, 7))); // true
}
}
Output:
3
7
Point[x=3, y=7]
true
The compiler generates a canonical constructor, accessors (no get prefix), and correct equals, hashCode, and toString implementations. Records are implicitly final and extend java.lang.Record.
Tip: Records work naturally with pattern matching and can implement interfaces, making them great building blocks for algebraic data modeling.
Sealed Classes
Sealed classes let you explicitly control which classes or interfaces are allowed to extend or implement a type. This makes class hierarchies exhaustive and intentional.
public sealed interface Shape
permits Circle, Rectangle, Triangle {}
public record Circle(double radius) implements Shape {}
public record Rectangle(double width, double height) implements Shape {}
public record Triangle(double base, double height) implements Shape {}
public class SealedDemo {
static double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
};
}
public static void main(String[] args) {
System.out.println(area(new Circle(5)));
System.out.println(area(new Rectangle(4, 6)));
}
}
Output:
78.53981633974483
24.0
The permits clause lists every allowed subtype. Each permitted subtype must be final, sealed, or non-sealed. Because the compiler knows the complete set of subtypes, the switch expression above is exhaustive without a default branch.
Note: Sealed classes and their permitted subtypes must live in the same package (or the same module if using JPMS). See Java 9 Modules for module details.
Pattern Matching for instanceof
Before Java 16, checking and casting an object required two lines. Pattern matching merges them:
public class PatternMatchDemo {
static void describe(Object obj) {
if (obj instanceof String s) {
// s is already a String here — no explicit cast needed
System.out.println("String of length " + s.length());
} else if (obj instanceof Integer i && i > 0) {
System.out.println("Positive integer: " + i);
} else {
System.out.println("Something else: " + obj);
}
}
public static void main(String[] args) {
describe("Hello");
describe(42);
describe(3.14);
}
}
Output:
String of length 5
Positive integer: 42
Something else: 3.14
The pattern variable (s, i) is in scope only within the branch where the match succeeds. This is finalized in Java 16 and fully stable in Java 17.
Switch Expressions (Finalized in Java 14, Stable in 17)
Switch expressions turn switch from a statement into an expression that returns a value. Java 17 ships them as fully stable.
public class SwitchExprDemo {
public static void main(String[] args) {
int day = 3;
String name = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
default -> "Weekend";
};
System.out.println(name);
}
}
Output:
Wednesday
The -> arrow form eliminates fall-through bugs. For multi-statement branches, use yield to return a value from a block:
String result = switch (day) {
case 1, 2, 3, 4, 5 -> {
System.out.println("Weekday");
yield "Weekday";
}
default -> "Weekend";
};
Text Blocks (Finalized in Java 15, Stable in 17)
Text blocks let you write multi-line string literals without escape sequences, making JSON, SQL, and HTML far more readable.
public class TextBlockDemo {
public static void main(String[] args) {
String json = """
{
"name": "Alice",
"age": 30,
"city": "Toronto"
}
""";
System.out.println(json);
}
}
Output:
{
"name": "Alice",
"age": 30,
"city": "Toronto"
}
The compiler strips the common leading indentation automatically (determined by the position of the closing """). Incidental whitespace disappears; intentional indentation remains.
Tip: Text blocks support the same escape sequences as regular strings (
\n,\t, etc.) plus two new ones:\<line-terminator>to suppress a newline, and\sto preserve a trailing space.
instanceof Pattern Matching in switch (Preview in Java 17)
Java 17 introduces pattern matching for switch as a preview feature. It lets you match on type and destructure in one step inside a switch:
// --enable-preview required for Java 17
public class SwitchPatternPreview {
static String format(Object obj) {
return switch (obj) {
case Integer i -> "int " + i;
case Long l -> "long " + l;
case Double d -> "double " + d;
case String s -> "string \"" + s + "\"";
default -> "other: " + obj;
};
}
public static void main(String[] args) {
System.out.println(format(42));
System.out.println(format(3.14));
System.out.println(format("hi"));
}
}
Output:
int 42
double 3.14
string "hi"
Warning: Preview features require
--enable-previewat both compile time and runtime. They are not yet guaranteed stable. Pattern matching forswitchwas finalized in Java 21 — see Java 21 LTS Features.
New java.util.random API (Pseudorandom Number Generators)
Java 17 introduces a new, unified PRNG API under java.util.random. The new RandomGenerator interface abstracts over many PRNG algorithms, and RandomGeneratorFactory lets you pick one by name.
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
public class NewRandomDemo {
public static void main(String[] args) {
// Use the fast, splittable L64X128MixRandom
RandomGenerator rng = RandomGeneratorFactory
.of("L64X128MixRandom")
.create();
rng.ints(5, 1, 101)
.forEach(System.out::println);
}
}
Output:
(5 random integers between 1 and 100)
The old java.util.Random, ThreadLocalRandom, and SplittableRandom now implement RandomGenerator, so existing code still compiles.
HexFormat Utility
java.util.HexFormat (new in Java 17) handles hex encoding and decoding without third-party libraries or hand-rolled loops.
import java.util.HexFormat;
public class HexFormatDemo {
public static void main(String[] args) {
HexFormat hex = HexFormat.of();
byte[] bytes = {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
String encoded = hex.formatHex(bytes);
System.out.println(encoded); // cafebabe
byte[] decoded = hex.parseHex("deadbeef");
System.out.println(decoded.length); // 4
}
}
Output:
cafebabe
4
HexFormat is immutable and thread-safe. It supports uppercase, delimiter separators, and prefix/suffix customization via withUpperCase(), withDelimiter(), etc.
Foreign Function & Memory API (Incubator)
Java 17 incubates the Foreign Function & Memory (FFM) API (jdk.incubator.foreign), the first step toward replacing JNI for calling native code. It lets you allocate off-heap memory and call C functions directly from Java without unsafe hacks.
Note: The FFM API graduated to preview in Java 19/20 and was finalized in Java 22. In Java 17 it requires
--add-modules jdk.incubator.foreign. Use it experimentally only.
Deprecations and Removals
Java 17 removes and deprecates several legacy features:
| Feature | Status | Replacement |
|---|---|---|
| Security Manager | Deprecated for removal | OS-level sandboxing / container isolation |
| Applet API | Deprecated for removal | Web-based alternatives |
| RMI Activation | Removed | Alternative RPC / gRPC |
sun.misc.Unsafe memory access | Partially deprecated | FFM API (preview) |
| Experimental AOT/JIT (GraalVM JVMCI) | No longer shipped in JDK | Standalone GraalVM |
Warning: The Security Manager (
java.lang.SecurityManager) is deprecated for removal in Java 17. Do not build new applications that rely on it.
Under the Hood
Sealed Classes and the Type System
At the bytecode level, sealed classes use two new class-file attributes: PermittedSubclasses (lists allowed subtypes) and Sealed (marks the class as sealed). The compiler uses these at compile time for exhaustiveness checks in switch and pattern matching. At runtime the JVM enforces that only listed subtypes can extend a sealed class — any other subclass triggers IncompatibleClassChangeError.
Records and the JVM
A record compiles to a final class extending java.lang.Record. The canonical constructor, accessors, equals, hashCode, and toString are generated directly in bytecode by the compiler (not reflectively at runtime), so they are as fast as hand-written versions. The equals and hashCode implementations use invokedynamic with a special bootstrap method — the JIT can inline and optimize these calls aggressively.
Pattern Matching and instanceof
The old obj instanceof Foo emits an instanceof bytecode instruction. Pattern matching for instanceof compiles to the same instanceof check followed by a checkcast — but the compiler guarantees the checkcast is redundant (it always succeeds), so the JIT eliminates it. The pattern variable is simply the result of the cast pinned into a local variable slot.
Text Blocks at Compile Time
Text blocks are a compile-time feature only — there is no new runtime type. The Java compiler processes leading whitespace and escape sequences during compilation and stores the result as a regular String constant in the constant pool. At runtime, text blocks are identical to ordinary string literals.
Related Topics
- Sealed Classes — deep dive into the
sealed/permits/non-sealedmodel - Records — immutable data classes explained in full
- Pattern Matching —
instanceofandswitchpattern matching details - Switch Expressions — arrow syntax,
yield, and exhaustiveness - Text Blocks — multi-line string literals and indentation rules
- Java 11 LTS Features — the previous LTS release with HttpClient, new String methods, and more
- Java 21 LTS Features — the next LTS with virtual threads, finalized pattern matching, and sequenced collections