Unlock Java 14: Master instanceof Pattern Matching, Switch Expressions, and Text Blocks
This article walks through the sixteen JDK 14 JEPs, focusing on JEP 305’s instanceof pattern matching, JEP 361’s switch expressions, and JEP 368’s text blocks, providing design motivations, code comparisons, step‑by‑step usage, and practical tips for modern Java development.
JDK 14 New Features Overview
JDK‑343: Packaging Tool (Incubator)
JDK‑345: G1 NUMA Memory Allocation Optimizations
JDK‑349: JFR Event Streaming
JDK‑352: Non‑Atomic Byte‑Buffer Mapping
JDK‑358: Friendly NullPointerExceptions
JDK‑359: Records (Preview)
JDK‑361: Switch Expressions (Standard)
JDK‑362: Deprecate Solaris and SPARC Ports
JDK‑363: Remove CMS Garbage Collector
JDK‑364: ZGC on macOS
JDK‑365: ZGC on Windows
JDK‑366: Deprecate ParallelScavenge + SerialOld GC combo
JDK‑367: Remove Pack200 Tools and API
JDK‑368: Text Blocks (Second Preview)
JDK‑370: External Storage API (Incubator)
JEP 305: instanceof Pattern Matching
JEP 305 adds pattern‑matching capabilities to the instanceof operator, allowing a type test and a cast to be expressed in a single, concise statement.
Design Intent
When code needs to branch based on an object's type, the traditional approach required a separate type check and a cast, leading to verbose and error‑prone code.
Traditional Approach
public void beforeWay(Object obj) {
// check type
if (obj instanceof String) {
// cast and use
String str = (String) obj;
System.out.println(str.length());
}
}Check the real type of obj.
If the check succeeds, cast obj to String.
Assign the cast value to a new local variable str.
Problems with this pattern include repetitive syntax, duplicated type names, and unnecessary temporary variables.
Verbose and cumbersome.
Type check and cast are performed separately.
The type name appears multiple times.
Redundant code.
JDK 14 introduces a streamlined form:
public void patternMatching(Object obj) {
if (obj instanceof String str) {
// <code>str</code> is already cast
System.out.println(str.length());
} else {
// <code>str</code> not available here
}
}Note: the bound variable str is only in scope inside the if block.
Simplifying equals()
Using pattern matching, equals() can be reduced to a single expression:
public class Student {
private String name;
public Student(String name) { this.name = name; }
@Override
public boolean equals(Object obj) {
return (obj instanceof Student s) && Objects.equals(this.name, s.name);
}
@Override
public int hashCode() { return Objects.hash(name); }
}This eliminates the need for an explicit cast and a separate null/type check.
JEP 361: Switch Expressions (Standard)
Switch expressions extend the traditional switch statement, allowing it to produce a value and eliminating the need for explicit break statements.
Design Intent
Java’s switch has evolved from Java 5 (enum support) to Java 7 (String support) and Java 11 (implicit fall‑through warnings). JDK 12 introduced the arrow syntax and expression form, which became standard in JDK 14.
Evolution of switch
Java 5+: enums are allowed.
Java 7+: String cases are allowed.
Java 11+: compiler warns about missing break.
Legacy switch example
public class Demo01 {
public static void main(String[] args) {
var score = 'C';
switch (score) {
case 'A': System.out.println("优秀"); break;
case 'B': System.out.println("良好"); break;
case 'C': System.out.println("中"); break;
case 'D': System.out.println("及格"); break;
case 'E': System.out.println("不及格"); break;
default: System.out.println("数据非法!");
}
}
}Missing break leads to fall‑through.
No‑break arrow syntax
public class Demo02 {
public static void main(String[] args) {
var score = 'C';
switch (score) {
case 'A' -> System.out.println("优秀");
case 'B' -> System.out.println("良好");
case 'C' -> System.out.println("中");
case 'D' -> System.out.println("及格");
case 'E' -> System.out.println("不及格");
default -> System.out.println("成绩数据非法!");
}
}
}Mixing old and new syntax causes a compilation error:
Switch as an expression
public class Demo03 {
public static void main(String[] args) {
var score = 'C';
String s = switch (score) {
case 'A' -> "优秀";
case 'B' -> "良好";
case 'C' -> "中";
case 'D' -> "及格";
case 'F' -> "不及格";
default -> "成绩输入错误";
};
System.out.println(s);
}
}The switch now yields a value that can be assigned directly.
Multiple case values
public class Demo04 {
public static void main(String[] args) {
var score = 'B';
String s = switch (score) {
case 'A', 'B' -> "上等";
case 'C' -> "中等";
case 'D', 'E' -> "下等";
default -> "成绩数据输入非法!";
};
System.out.println(s);
}
}Yielding a value
When a case needs a block, the block must end with a yield statement to produce the expression’s value.
public void print(int days) {
var score = 'B';
String result = switch (score) {
case 'A', 'B' -> "上等";
case 'C' -> "中等";
case 'D', 'E' -> "下等";
default -> {
if (score > 100) {
yield "数据不能超过100";
} else {
yield score + "此分数低于0分";
}
}
};
System.out.println(result);
}Switch expressions cannot contain break; each arm must produce a value or throw an exception. They must be exhaustive, usually requiring a default clause unless the selector is an enum that is fully covered.
JEP 368: Text Blocks
Introduction
Text blocks simplify the creation of multi‑line string literals, improving readability for large pieces of text such as JSON, HTML, or SQL.
Design Intent
Introduced as a preview in JDK 13 (JEP 355) and refined in JDK 14, a text block is delimited by three double‑quote characters.
Description
A text block starts with """, may be followed by optional spaces, and ends with another """. The content begins after the line‑terminator of the opening delimiter and ends before the closing delimiter. Indentation is automatically stripped based on the minimal common whitespace.
Basic example
line 1
line 2
line 3Equivalent to the traditional string literal:
"line 1
line 2
line 3
"HTML example
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";SQL example
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";Multilingual script example
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("""
function hello() {
print('"Hello, world"');
}
hello();
""");Text blocks also support two special escape sequences: \ to suppress a line break and \s to insert a single space without affecting trailing whitespace handling.
These new JDK 14 features reduce boilerplate, make code clearer, and enable developers to write more expressive Java programs.
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.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
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.
