New Features of JDK 17: Text Blocks, Enhanced NPE, Records, Switch Expressions and More
This article introduces the most useful JDK 17 language enhancements—including text blocks, improved NullPointerException messages, records, switch expressions, private interface methods, pattern matching, collection factory methods, new String APIs, Stream API extensions, the modern HttpClient, JShell, direct java file execution, and the Z Garbage Collector—providing code examples and practical guidance for Java developers.
Introduction
Java versions evolve rapidly; while JDK 20 is the latest, JDK 8 remains the most widely used in production. The author shares personal experience of upgrading to JDK 17 after seeing its new syntax features.
1. JDK 17 Language Features
1.1 Text Blocks
Text blocks simplify writing multi‑line strings such as JSON, HTML, or SQL, eliminating cumbersome concatenation.
/**
* 使用JDK8返回HTML文本
*
* @return 返回HTML文本
*/
public static final String getHtmlJDK8() {
return "<html>
" +
" <body>
" +
" <p>Hello, world</p>
" +
" </body>
" +
"</html>";
}With JDK 17 the same method can be written using a text block:
/**
* 使用JDK17返回HTML文本
*
* @return 返回HTML文本
*/
public static final String getHtmlJDK17() {
return """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
}1.2 Enhanced NullPointerException
JDK 17 provides more detailed NPE messages, helping developers locate the exact null reference.
public static void main(String[] args) {
try {
// 简单的空指针
String str = null;
str.length();
} catch (Exception e) {
e.printStackTrace();
}
try {
// 复杂一点的空指针
var arr = List.of(null);
String str = (String)arr.get(0);
str.length();
} catch (Exception e) {
e.printStackTrace();
}
}1.3 Records
Records provide a concise syntax for data‑carrier classes, reducing boilerplate getter/setter code.
package com.summo.jdk17;
public record StudentRecord(Long stuId,
String stuName,
int stuAge,
String stuGender,
String stuEmail) {
public StudentRecord {
System.out.println("构造函数");
}
public static void main(String[] args) {
StudentRecord record = new StudentRecord(1L, "张三", 16, "男", "[email protected]");
System.out.println(record);
}
}1.4 Switch Expressions
Since JDK 12, switch became an expression with a return value; JDK 17 adds pattern matching, yield, and arrow syntax.
package com.summo.jdk17;
public class SwitchDemo {
public int getByJDK8(Week week) {
int i = 0;
switch (week) {
case MONDAY, TUESDAY: i = 1; break;
case WEDNESDAY: i = 3; break;
case THURSDAY: i = 4; break;
case FRIDAY: i = 5; break;
case SATURDAY: i = 6; break;
case SUNDAY: i = 7; break;
default: i = 0; break;
}
return i;
}
public int getByJDK17(Week week) {
return switch (week) {
case null -> -1;
case MONDAY -> 1;
case TUESDAY -> 2;
case WEDNESDAY -> 3;
case THURSDAY -> { yield 4; }
case FRIDAY -> 5;
case SATURDAY, SUNDAY -> 6;
default -> 0;
};
}
private enum Week { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
}1.5 Private Interface Methods
Java 17 allows private methods inside interfaces, enabling better decomposition of large default methods.
public interface PrivateInterfaceMethod {
/**
* 接口默认方法
*/
default void defaultMethod() {
privateMethod();
}
// 接口私有方法,在Java8里面是不被允许的
private void privateMethod() {
}
}1.6 Pattern Matching for instanceof
Pattern matching removes the need for explicit casts.
/**
* 旧式写法
*/
public void matchByJDK8(Object value) {
if (value instanceof String) {
String v = (String) value;
System.out.println("遇到一个String类型" + v.toUpperCase());
} else if (value instanceof Integer) {
Integer v = (Integer) value;
System.out.println("遇到一个整型类型" + v.longValue());
}
}
/**
* 新写法
*/
public void matchByJDK17(Object value) {
if (value instanceof String v) {
System.out.println("遇到一个String类型" + v.toUpperCase());
} else if (value instanceof Integer v) {
System.out.println("遇到一个整型类型" + v.longValue());
}
}1.7 Collection Factory Methods
Creating small immutable collections is now a one‑liner.
// JDK8 style
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
// JDK17 style
Set<String> set = Set.of("a", "b", "c");2. Other New Features
2.1 New String Methods
repeat: repeat a string. isBlank: check for blank strings without external libraries. strip: trim whitespace including full‑width characters. lines: obtain a stream of lines. indent: add indentation. transform: apply a function to the string.
2.2 Stream API Enhancements
Added takeWhile, dropWhile, ofNullable, the three‑argument iterate, and toList for more functional style.
// takeWhile example
List<Integer> list = Stream.of(2,2,3,4,5,6,7,8,9,10)
.takeWhile(i -> (i % 2 == 0)).toList(); // [2, 2]
// dropWhile example
List<Integer> list1 = Stream.of(2,2,3,4,5,6,7,8,9,10)
.dropWhile(i -> (i % 2 == 0)).toList(); // [3,4,5,6,7,8,9,10]
var nullStreamCount = Stream.ofNullable(null).count(); // 0
Stream.iterate(0, n -> n < 10, n -> n + 1).forEach(System.out::println);
Stream.iterate(0, n -> n + 1).limit(10).forEach(System.out::println);2.3 New HttpClient
The modern HttpClient (standard since JDK 11) offers a fluent API for both synchronous and asynchronous requests.
// Synchronous request
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
.authenticator(Authenticator.getDefault())
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
// Asynchronous request
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://foo.com/"))
.timeout(Duration.ofMinutes(2))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);2.4 JShell
JShell provides an interactive REPL for Java, allowing quick experimentation without creating full projects.
2.5 Direct Execution of Java Files
Since JDK 11 you can run a single source file directly:
java MyProgram.java2.6 Z Garbage Collector (ZGC)
ZGC, introduced in JDK 11 and stable in later releases, aims for pause times under 10 ms even with heap sizes up to 16 TB, making it suitable for low‑latency workloads.
3. Conclusion
Keeping up with Java releases is essential; many projects are already migrating from Java 8 to Java 17 (e.g., Spring Boot 3.0). Leveraging the new language features and runtime improvements can greatly enhance code readability, maintainability, and performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
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.
