Unlock Java’s Latest Power: Practical Guide to New Features from Java 9‑17
This article provides a concise, hands‑on overview of Java’s most useful language enhancements from Java 9 through Java 17—including private interface methods, Optional API upgrades, Stream API additions, var type inference, the new HTTP client, switch expressions, text blocks, records, instanceof pattern matching, and sealed classes—complete with clear code examples for each feature.
Introduction
The article presents a practical checklist of useful Java language features introduced from Java 9 to Java 17, focusing on real‑world coding benefits rather than low‑level runtime optimizations.
Private Interface Methods (Java 9)
Before Java 9, interfaces could only contain abstract methods and default methods. Java 9 adds
privatemethods, allowing shared logic between default methods without code duplication.
public interface MyInterface {
default void method1() {
System.out.println("Default method1");
commonMethod();
}
default void method2() {
System.out.println("Default method2");
commonMethod();
}
private void commonMethod() {
System.out.println("Common method in the interface");
}
}Optional API Enhancements (Java 9)
Java 9 introduces
stream(),
ifPresentOrElse(),
or(), and
isEmpty()methods, simplifying optional handling.
Optional<String> optional = ...;
optional.stream().map(String::length).forEach(System.out::println);
optional.ifPresentOrElse(v -> System.out.println("Value is present: " + v),
() -> System.out.println("Value is absent"));
Optional<String> backup = Optional.of("Backup value");
Optional<String> result = optional.or(() -> backup);
System.out.println(result.get());
if (optional.isEmpty()) {
System.out.println("Optional is empty");
}Stream API Enhancements (Java 9)
New methods
takeWhile(),
dropWhile(),
ofNullable(), and an overloaded
iterate()give finer control over stream processing.
Stream.of("a","b","c","de","f")
.takeWhile(s -> s.length() == 1)
.forEach(System.out::print); // prints abc
Stream.of("a","b","c","de","f")
.dropWhile(s -> s.length() == 1)
.forEach(System.out::print); // prints def
Stream.ofNullable(null).forEach(System.out::print);
Stream<Integer> stream = Stream.iterate(1, n -> n < 10, n -> n * 2);
stream.forEach(System.out::print); // prints 1248Local Variable Type Inference (Java 10)
The
varkeyword lets the compiler infer the type of local variables, reducing boilerplate.
var str = "Hello, World!"; // String
var num = 123; // int
var list = new ArrayList<String>(); // ArrayList<String>
for (var i = 0; i < 10; i++) {
System.out.println(i);
}
try (var reader = new BufferedReader(new FileReader("file.txt"))) {
// use reader
}New HTTP Client (Java 11)
Java 11 replaces
HttpURLConnectionwith a modern, asynchronous‑friendly HTTP client API.
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://example.com"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
CompletableFuture<HttpResponse<String>> future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
future.thenAccept(r -> {
System.out.println(r.statusCode());
System.out.println(r.body());
});Switch Expression Enhancements (Java 12)
Switch can now be used as an expression, yielding a value directly.
int day = 2;
String dayOfWeek = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> throw new IllegalArgumentException("Invalid day of week: " + day);
};
System.out.println(dayOfWeek); // Prints "Tuesday"Text Blocks (Java 13)
Multi‑line string literals are now possible with text blocks, supporting optional interpolation via
${}.
String html = """
<html>
<body>
<p>Hello, ${name}</p>
</body>
</html>
""";
System.out.println(html);Record Classes (Java 14)
Records provide a concise way to declare immutable data carriers.
public record Point(int x, int y) { }Instanceof Pattern Matching (Java 16)
The
instanceofoperator can now bind a variable, eliminating explicit casts.
Object obj = ...;
if (obj instanceof String str) {
System.out.println(str.length());
}Sealed Classes and Interfaces (Java 17)
Sealed types restrict which classes may extend or implement them, improving type safety.
public sealed abstract class Shape permits Circle, Square { }
public final class Circle extends Shape { }
public final class Square extends Shape { }These features collectively make modern Java code more concise, expressive, and maintainable.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.