Comprehensive Overview of JDK 14 New Features
JDK 14 introduced 16 JEPs (JDK Enhancement Proposals), with several notable enhancements and deprecations.
- JEP 343: Packaging Tool (Incubator)
- JEP 345: NUMA-aware Memory Allocation for G1
- JEP 349: JFR Event Streaming
- JEP 352: Non-atomic Byte Buffer Mappings
- JEP 358: More Helpful Null Pointer Exceptions
- JEP 359: Records (Preview)
- JEP 361: Switch Expressions (Standard)
- JEP 362: Deprecation of Solaris and SPARC Ports
- JEP 363: Removal of CMS Garbage Collector
- JEP 364: ZGC on macOS
- JEP 365: ZGC on Windows
- JEP 366: Deprecation of ParallelScavenge + SerialOld GC Combination
- JEP 367: Removal of Pack200 Tools and API
- JEP 368: Text Blocks (Second Preview)
- JEP 370: Foreign Function & Memory API (Incubator)
Pattern Matching with instanceof
JEP 305 enhances the instanceof operator to support pattern matching, reducing boilerplate code in type checks and casts.
Before:
public void beforeCheck(Object obj) {
if (obj instanceof String) {
String str = (String) obj;
System.out.println(str.length());
}
}
After (JDK 14):
public void usePatternMatching(Object obj) {
if (obj instanceof String str) {
System.out.println(str.length());
}
}
The variable str is only accessible within the if block and is automatically cast up on a succesfull type check. This eliminates redundant type declarations and improves readability.
This pattern also simplifies equals() implementations:
@Override
public boolean equals(Object obj) {
return (obj instanceof Student s) && Objects.equals(this.name, s.name);
}
Enhanced Switch Expressions (JEP 361)
Switch expressions are now standard in JDK 14, evolving from previews in JDK 12 and 13.
Traditional switch
switch (score) {
case 'A': System.out.println("Excellent"); break;
case 'B': System.out.println("Good"); break;
case 'C': System.out.println("Average"); break;
default: System.out.println("Invalid");
}
Arrow syntax (no fall-through)
switch (score) {
case 'A' -> System.out.println("Excellent");
case 'B' -> System.out.println("Good");
case 'C' -> System.out.println("Average");
default -> System.out.println("Invalid");
}
As an expression
String result = switch (score) {
case 'A' -> "Excellent";
case 'B' -> "Good";
case 'C' -> "Average";
default -> "Invalid";
};
System.out.println(result);
Multiple values in one case
String level = switch (grade) {
case 'A', 'B' -> "Top Tier";
case 'C' -> "Middle";
case 'D', 'E' -> "Low";
default -> "Invalid";
};
Using yield in blocks
String response = switch (status) {
case 200 -> "OK";
case 404 -> "Not Found";
default -> {
if (status > 500) {
yield "Server Error";
} else {
yield status + " Client Error";
}
}
};
Each case must produce a value or throw an exception. The compiler enforces exhaustive coverage unless using enums with all known values explicitly handled.
Text Blocks (JEP 368)
Text blocks provide multi-line string literals using triple quotes (`"""").
Basic syntax
String xml = """
<root>
<a>Hello</a>
<b>
<c>World</c>
</b>
</root>
""";
Leading whitespace is automatically trimmed based on the minimum indentation across all lines. The ending delimiter’s position determines how many spaces are removed.
Escape sequences
\suppresses line breaks.\sinserts a single space.
Example:
String longLine = """
hello \
world \
goodbye
""";
This results in a single logical line.
Practical examples
HTML:
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
SQL query:
String query = """
SELECT EMP_ID, LAST_NAME FROM EMPLOYEE_TB
WHERE CITY = 'INDIANAPOLIS'
ORDER BY EMP_ID, LAST_NAME;
""";
JavaScript script:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object result = engine.eval("""
function hello() {
print('"Hello, world"');
}
hello();
""");
Text blocks improve code clarity and reduce manual concatenation or escape sequences.