
Java 14 Features You Should Know
Java 14, released in March 2020, brought several significant enhancements to the language that developers and system administrators should definitely know about. While it wasn’t an LTS release, it introduced features that shaped future Java development and provided practical solutions for common programming challenges. This post covers the key features that can improve your code quality, development productivity, and application performance on your production servers.
Switch Expressions (Standard Feature)
Switch expressions, which were previewed in Java 12 and 13, became a standard feature in Java 14. Unlike traditional switch statements, switch expressions return values and support the new arrow syntax, making your code more concise and less error-prone.
// Traditional switch statement
String dayType;
switch (day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
dayType = "Weekday";
break;
case SATURDAY:
case SUNDAY:
dayType = "Weekend";
break;
default:
throw new IllegalArgumentException("Invalid day: " + day);
}
// Java 14 switch expression
String dayType = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
case SATURDAY, SUNDAY -> "Weekend";
};
The new syntax eliminates the need for break statements and allows multiple case labels in a single branch. You can also use yield for more complex expressions:
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> {
System.out.println("Calculating letters for: " + day);
yield day.toString().length();
}
};
Pattern Matching for instanceof (Preview)
Pattern matching for instanceof was introduced as a preview feature in Java 14, addressing the common pattern of type checking followed by casting. This feature reduces boilerplate code and eliminates potential ClassCastException errors.
// Before Java 14
if (obj instanceof String) {
String str = (String) obj;
System.out.println(str.toUpperCase());
}
// Java 14 pattern matching
if (obj instanceof String str) {
System.out.println(str.toUpperCase());
}
The pattern variable is only in scope when the instanceof check succeeds. This works particularly well in complex conditional logic:
public static String formatValue(Object obj) {
if (obj instanceof Integer i && i > 100) {
return "Large number: " + i;
} else if (obj instanceof String s && s.length() > 10) {
return "Long string: " + s.substring(0, 10) + "...";
} else if (obj instanceof Double d) {
return String.format("%.2f", d);
}
return obj.toString();
}
Records (Preview Feature)
Records provide a compact syntax for creating immutable data carrier classes. They automatically generate constructors, accessors, equals(), hashCode(), and toString() methods, significantly reducing boilerplate code.
// Traditional data class
public class PersonOld {
private final String name;
private final int age;
public PersonOld(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public boolean equals(Object obj) {
// ... boilerplate code
}
@Override
public int hashCode() {
// ... boilerplate code
}
@Override
public String toString() {
// ... boilerplate code
}
}
// Java 14 record
public record Person(String name, int age) {}
Records are particularly useful for DTOs, configuration objects, and data transfer between layers:
public record ServerConfig(String host, int port, boolean sslEnabled) {
// Custom constructor with validation
public ServerConfig {
if (port < 1 || port > 65535) {
throw new IllegalArgumentException("Invalid port: " + port);
}
}
// Additional methods
public String getConnectionString() {
return (sslEnabled ? "https://" : "http://") + host + ":" + port;
}
}
// Usage
ServerConfig config = new ServerConfig("localhost", 8080, true);
System.out.println(config.getConnectionString()); // https://localhost:8080
Text Blocks (Standard Feature)
Text blocks, previewed in Java 13, became standard in Java 14. They provide a cleaner way to write multi-line strings, especially useful for SQL queries, JSON, HTML, or configuration files.
// Traditional string concatenation
String html = "\n" +
" \n" +
" Hello World
\n" +
" \n" +
"";
// Java 14 text block
String html = """
Hello World
""";
// SQL queries become much more readable
String query = """
SELECT u.name, u.email, p.title
FROM users u
JOIN posts p ON u.id = p.user_id
WHERE u.active = true
AND p.published_date > ?
ORDER BY p.published_date DESC
""";
Helpful NullPointerExceptions
Java 14 improved NullPointerException messages by pinpointing exactly which variable was null in complex expressions. This feature significantly reduces debugging time in production environments.
// Consider this code
String result = person.getAddress().getStreet().toUpperCase();
// Before Java 14
Exception in thread "main" java.lang.NullPointerException
at Main.main(Main.java:10)
// Java 14 and later
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "Address.getStreet()" because the return value of
"Person.getAddress()" is null
at Main.main(Main.java:10)
To enable this feature on VPS or dedicated servers, use the -XX:+ShowCodeDetailsInExceptionMessages JVM flag:
java -XX:+ShowCodeDetailsInExceptionMessages MyApplication
JFR Event Streaming
Java Flight Recorder (JFR) Event Streaming allows real-time monitoring of JVM events without writing data to disk first. This is particularly valuable for production monitoring and observability.
import jdk.jfr.consumer.RecordingStream;
// Monitor garbage collection events in real-time
try (var stream = new RecordingStream()) {
stream.enable("jdk.GarbageCollection")
.withThreshold(Duration.ofMillis(10));
stream.onEvent("jdk.GarbageCollection", event -> {
System.out.println("GC Event: " + event.getString("name") +
", Duration: " + event.getDuration("duration"));
});
stream.start(); // Non-blocking
}
Foreign Memory Access API (Incubator)
The Foreign Memory Access API provides a safe and efficient way to access memory outside the Java heap. This is useful for interacting with native libraries or managing large datasets.
import jdk.incubator.foreign.*;
// Allocate native memory
try (MemorySegment segment = MemorySegment.allocateNative(1024)) {
MemoryAddress address = segment.baseAddress();
// Write data
MemoryAccess.setIntAtOffset(segment, 0, 42);
MemoryAccess.setIntAtOffset(segment, 4, 84);
// Read data
int value1 = MemoryAccess.getIntAtOffset(segment, 0); // 42
int value2 = MemoryAccess.getIntAtOffset(segment, 4); // 84
}
Performance and Best Practices
Here’s a comparison of Java 14 features and their performance impact:
Feature | Performance Impact | Best Use Case | Production Ready |
---|---|---|---|
Switch Expressions | Slight improvement | Complex conditional logic | Yes |
Pattern Matching instanceof | Minor improvement | Type checking and casting | Preview (use with –enable-preview) |
Records | Reduced memory footprint | DTOs and immutable data | Preview (use with –enable-preview) |
Text Blocks | No impact | Multi-line strings | Yes |
JFR Event Streaming | Low overhead monitoring | Production observability | Yes |
Common Issues and Troubleshooting
When upgrading to Java 14, you might encounter these issues:
- Preview Features: Records and pattern matching require –enable-preview flag and –source 14
- IDE Support: Ensure your IDE supports Java 14 preview features
- Build Tools: Update Maven/Gradle configurations for preview features
- Dependency Conflicts: Some libraries may not be compatible with Java 14
# Maven configuration for preview features
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
14
--enable-preview
# Gradle configuration
tasks.withType(JavaCompile) {
options.compilerArgs += ["--enable-preview"]
}
tasks.withType(Test) {
jvmArgs += ["--enable-preview"]
}
Real-World Implementation Example
Here’s a practical example combining multiple Java 14 features in a REST API service:
public record ApiResponse(int status, String message, Object data) {}
public record UserRequest(String name, String email, int age) {
public UserRequest {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age: " + age);
}
}
}
public class UserService {
public ApiResponse processUser(Object request) {
return switch (validateRequest(request)) {
case VALID -> {
if (request instanceof UserRequest user) {
// Process valid user
yield new ApiResponse(200, "User created", user);
}
yield new ApiResponse(500, "Internal error", null);
}
case INVALID_AGE -> new ApiResponse(400, "Invalid age provided", null);
case INVALID_EMAIL -> new ApiResponse(400, "Invalid email format", null);
case MISSING_DATA -> new ApiResponse(400, "Missing required fields", null);
};
}
private ValidationResult validateRequest(Object obj) {
if (obj instanceof UserRequest user) {
if (user.email() == null || !user.email().contains("@")) {
return ValidationResult.INVALID_EMAIL;
}
if (user.age() < 18) {
return ValidationResult.INVALID_AGE;
}
return ValidationResult.VALID;
}
return ValidationResult.MISSING_DATA;
}
}
enum ValidationResult { VALID, INVALID_AGE, INVALID_EMAIL, MISSING_DATA }
For more detailed information about Java 14 features, check the official OpenJDK documentation. The Oracle Java 14 language changes guide provides comprehensive coverage of all language enhancements.
While Java 14 wasn't an LTS release, its features laid important groundwork for future versions. Many of these preview features became standard in later releases, making Java 14 knowledge valuable for long-term Java development strategy on enterprise servers and cloud deployments.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.