Java JDK 12‑17 New Features and Enhancements Overview
This article provides a comprehensive overview of the major language and runtime enhancements introduced in JDK 12 through JDK 17, covering switch expressions, micro‑benchmarking with JMH, class‑data sharing, garbage‑collector improvements, new String methods, hidden and sealed classes, records, and unified asynchronous logging, all illustrated with code examples.
1.1 Switch Expression Syntax Changes
Before JDK 12, forgetting a break in a switch caused fall‑through. JDK 12 introduces arrow syntax ( -> ) that eliminates fall‑through without a break , allows switch to be used as an expression, supports multiple case values, and adds the yield statement (JDK 13) to return a value from a switch expression.
public class Demo{
public static void main(String[] args){
var score = 'C';
String s = switch (score){
case 'A', 'B' -> "上等";
case 'C' -> "中等";
case 'D', 'E' -> "下等";
default -> {
if (score > 100) {
yield "数据不能超过100";
} else {
yield score + "此分数低于0分";
}
};
};
}
}1.2 Micro‑Benchmark Suite (JMH)
JMH (Java Microbenchmark Harness) is a dedicated tool for measuring the performance of small code fragments. Typical scenarios include measuring method execution time and comparing two implementations of an interface.
Adding JMH Dependencies
<properties>
<jmh.version>1.14.1</jmh.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>Benchmark Code Example
import org.openjdk.jmh.annotations.*;
@State(Scope.Thread)
public class MyBenchmark {
@Benchmark
@BenchmarkMode(Mode.All)
public void testMethod() throws InterruptedException {
Thread.sleep(300);
}
@Benchmark
@BenchmarkMode(Mode.All)
public void testMethod2() throws InterruptedException {
Thread.sleep(600);
}
} import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
public class BenchmarkRunner {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.forks(1)
.warmupIterations(5)
.measurementIterations(5)
.build();
new Runner(opt).run();
}
}Typical JMH result metrics include throughput (thrpt), average time (avgt), sample time, and single‑shot time (ss). Annotations such as @BenchmarkMode , @State , @OutputTimeUnit , and @Benchmark control the benchmark behavior.
1.3 Class‑Data Sharing (CDS) Optimizations
CDS reduces JVM startup cost and memory usage by sharing core classes among multiple JVM instances. JDK 12 makes CDS archives the default on 64‑bit platforms, while JDK 13 adds dynamic archiving with -XX:ArchiveClassesAtExit and reuse via -XX:SharedArchiveFile .
1.4 G1 and ZGC Enhancements
JDK 12 allows G1 to abort a collection that would exceed -XX:MaxGCPauseMillis and introduces a mixed‑GC mode that separates mandatory and optional regions.
G1 can return unused heap memory to the OS when the application is idle.
JDK 13 enables ZGC to release unused memory (toggleable with -XX:-ZUncommit ) and supports heaps up to 16 TB.
ZGC, introduced as experimental in JDK 11 and finalized in JDK 15, is suitable for very large heaps and low‑pause requirements.
1.5 Shenandoah GC
Shenandoah, experimental in JDK 12 and production‑ready in JDK 15, performs concurrent evacuation to keep pause times independent of heap size, targeting 99.9 % of pauses under 10 ms. It differs from ZGC in implementation details and development origin.
1.6 New String Methods
transform(Function) – applies a function and returns the result.
indent(int) – adjusts indentation of a multi‑line string.
var rs = "test".transform(s -> s + "Java").transform(s -> s.toUpperCase()); // TESTJAVA
String result = "Java\njava\ntest".indent(3);1.7 Files.mismatch
Returns the index of the first differing byte between two files.
System.out.println(Files.mismatch(Path.of("a.txt"), Path.of("b.txt")));1.8 Compact Number Formatting
NumberFormat now supports compact number styles (e.g., 1 K, 1 M). Example for US and Chinese locales is shown.
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
System.out.println(fmt.format(1000)); // 1K
var cnf = NumberFormat.getCompactNumberInstance(Locale.CHINA, NumberFormat.Style.SHORT);
System.out.println(cnf.format(5_0000)); // 5万1.9 Unicode Support
JDK 12 supports Unicode 11.0, JDK 13 adds 12.1, and JDK 14‑17 support Unicode 13.0.
1.10 Enhanced Null‑Pointer Exceptions
Since JDK 14, NPE messages indicate the exact variable that was null, improving debugging.
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "String.charAt(int)" because "str" is null
at com.qf.jdk14.Test.main(Test.java:11)1.11 Text Blocks
Introduced as a preview in JDK 13, finalized in JDK 15, text blocks allow multi‑line string literals without explicit escaping. The opening delimiter is """ , and the closing delimiter determines the final newline handling.
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";1.12 Reimplemented Socket API
JDK 13 replaces the legacy SocketImpl with NioSocketImpl , using NIO internals, eliminating native code, integrating with buffer caching, and employing java.util.concurrent locks for better concurrency. The old implementation can be re‑enabled with -Djdk.net.usePlainSocketImpl=true .
1.13 Hidden Classes
Hidden classes allow frameworks and lambda expressions to generate runtime classes that are not visible to the application class loader, improving lifecycle management and reducing visibility.
1.14 Enhanced instanceof
Since JDK 16, pattern matching with instanceof combines type check and cast: if (obj instanceof String s) { ... } .
Object value = data.get("test");
if (value instanceof String s) {
System.out.println(s.substring(1));
}1.15 Records
Records provide a compact syntax for immutable data carriers. The compiler automatically generates constructors, accessors, equals , hashCode , and toString .
public record User(String username, String password) {}1.16 Sealed Classes
Sealed classes restrict which classes may extend them, improving encapsulation. Example shows a sealed class Human permitting three subclasses, with a mix of non‑sealed , sealed , and final subclasses.
sealed class Human permits Kyrie, LeBron, George { ... }
non‑sealed class Kyrie extends Human { ... }
sealed class LeBron extends Human { ... }
final class George extends Human { ... }1.17 Unified Asynchronous Logging
JDK 17 adds an async logging mode ( -Xlog:async ) that buffers log records and flushes them asynchronously, reducing the impact of logging on application performance.
Summary
From JDK 11 to JDK 17, Java has introduced a series of language and runtime enhancements, culminating in the LTS release of JDK 17. These changes improve developer productivity, performance, and reliability, reflecting Java’s ongoing evolution to meet modern programming demands.
References
https://openjdk.org/projects/jdk/
JDK12: JDK12新功能深度解析_jdk12新特性-CSDN博客
switch statement - What does the new keyword "yield" mean in Java 13? - Stack Overflow
New Features in Java 13 | Baeldung
Java 11 and 12 - New Features (packtpub.com)
Java 16 and IntelliJ IDEA | The IntelliJ IDEA Blog (jetbrains.com)
Sealed Class in Java - GeeksforGeeks
政采云技术
ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.