Java New Features since Java 8
Java Version Timeline

Java 8 Features
Lambda Expressions
// Before Java 8
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Java 8 Lambda
Runnable r2 = () -> System.out.println("Hello");
// Lambda syntax
(parameters) -> expression
(parameters) -> { statements; }
// Examples
Comparator<String> comp = (s1, s2) -> s1.compareTo(s2);
Consumer<String> printer = s -> System.out.println(s);
Function<String, Integer> length = s -> s.length();
Predicate<Integer> isEven = n -> n % 2 == 0;
Supplier<Double> random = () -> Math.random();
BinaryOperator<Integer> add = (a, b) -> a + b;
Method References
// Types of method references
// 1. Static method
Function<String, Integer> parser = Integer::parseInt;
// 2. Instance method of particular object
String str = "Hello";
Supplier<Integer> lengthSupplier = str::length;
// 3. Instance method of arbitrary object
Function<String, Integer> lengthFunc = String::length;
// 4. Constructor
Supplier<ArrayList<String>> listFactory = ArrayList::new;
Function<Integer, int[]> arrayFactory = int[]::new;
// Practical examples
list.forEach(System.out::println);
list.sort(Comparator.comparing(Person::getName));
list.stream().map(String::toUpperCase).collect(Collectors.toList());
Streams API
List<String> filtered = list.stream()
.filter(s -> s.startsWith("A"))
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
// See Java_04_Streams.md for full details
Optional
// Creating Optional
Optional<String> opt1 = Optional.of("value"); // Non-null
Optional<String> opt2 = Optional.ofNullable(null); // May be null
Optional<String> opt3 = Optional.empty(); // Empty
// Checking and getting
opt1.isPresent(); // true
opt1.isEmpty(); // false (Java 11+)
opt1.get(); // "value" (throws if empty)
opt1.orElse("default"); // Value or default
opt1.orElseGet(() -> "computed"); // Value or computed default
opt1.orElseThrow(); // Value or NoSuchElementException
opt1.orElseThrow(() -> new CustomException());
// Transforming
opt1.map(String::toUpperCase); // Optional<String>
opt1.flatMap(s -> Optional.of(s.length())); // Unwrap nested Optional
opt1.filter(s -> s.length() > 3); // Filter value
// Conditional actions
opt1.ifPresent(System.out::println);
opt1.ifPresentOrElse( // Java 9+
System.out::println,
() -> System.out.println("Empty")
);
// Chaining (Java 9+)
opt1.or(() -> Optional.of("fallback")); // Alternative Optional
Default Methods in Interfaces
public interface Vehicle {
void start();
// Default method with implementation
default void honk() {
System.out.println("Beep!");
}
// Static method in interface
static Vehicle create() {
return new Car();
}
}
Date/Time API (java.time)
// Core classes
LocalDate date = LocalDate.now();
LocalDate specific = LocalDate.of(2024, 1, 15);
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("America/New_York"));
Instant instant = Instant.now();
// Operations
date.plusDays(5);
date.minusMonths(1);
date.withYear(2025);
date.isAfter(otherDate);
// Duration and Period
Duration duration = Duration.between(time1, time2);
Period period = Period.between(date1, date2);
// Formatting
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String formatted = dateTime.format(formatter);
LocalDateTime parsed = LocalDateTime.parse("2024-01-15 10:30", formatter);
Java 9 Features
Module System (JPMS)
// module-info.java
module com.myapp {
requires java.sql;
requires transitive java.logging;
exports com.myapp.api;
exports com.myapp.internal to com.myapp.tests;
opens com.myapp.models to com.google.gson;
provides com.myapp.spi.Plugin with com.myapp.impl.MyPlugin;
uses com.myapp.spi.Plugin;
}
Collection Factory Methods
// Immutable collections
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);
Map<String, Integer> map2 = Map.ofEntries(
Map.entry("a", 1),
Map.entry("b", 2)
);
// Note: These are immutable, null not allowed
Stream Improvements
// takeWhile and dropWhile
Stream.of(1, 2, 3, 4, 5).takeWhile(n -> n < 4); // 1, 2, 3
Stream.of(1, 2, 3, 4, 5).dropWhile(n -> n < 4); // 4, 5
// iterate with predicate
Stream.iterate(1, n -> n < 100, n -> n * 2); // 1, 2, 4, 8, 16, 32, 64
// ofNullable
Stream.ofNullable(nullableValue); // Empty or single-element stream
Private Interface Methods
public interface MyInterface {
default void publicMethod() {
privateHelper();
}
private void privateHelper() {
// Implementation
}
private static void privateStaticHelper() {
// Static helper
}
}
Try-with-resources Enhancement
// Before Java 9
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
// use reader
}
// Java 9: Can use effectively final variables
BufferedReader reader = new BufferedReader(new FileReader(file));
try (reader) { // reader is effectively final
// use reader
}
Java 10 Features
Local Variable Type Inference (var)
// var infers type from right side
var list = new ArrayList<String>(); // ArrayList<String>
var map = Map.of("a", 1); // Map<String, Integer>
var stream = list.stream(); // Stream<String>
// Useful for complex generic types
var entries = map.entrySet(); // Set<Map.Entry<String, Integer>>
// Where var CANNOT be used
// var x; // No initializer
// var x = null; // Cannot infer type
// var x = () -> {}; // Lambda needs target type
// var x = { 1, 2, 3 }; // Array initializer needs type
// Instance/static fields
// Method parameters
// Return types
Java 11 Features (LTS)
New String Methods
String str = " Hello World ";
str.isBlank(); // false (checks whitespace)
str.strip(); // "Hello World" (Unicode-aware trim)
str.stripLeading(); // "Hello World "
str.stripTrailing(); // " Hello World"
str.repeat(3); // " Hello World Hello World Hello World "
str.lines(); // Stream of lines
"".isBlank(); // true
" ".isBlank(); // true
HTTP Client (Standard)
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"key\":\"value\"}"))
.build();
// Synchronous
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
// Asynchronous
CompletableFuture<HttpResponse<String>> futureResponse = client.sendAsync(
request, HttpResponse.BodyHandlers.ofString());
Files Methods
// Read/write string directly
String content = Files.readString(Path.of("file.txt"));
Files.writeString(Path.of("file.txt"), "content");
Running Single-File Programs
# Run Java file directly without compiling
java HelloWorld.java
Java 14-16 Features
Records (Java 16)
// Immutable data class with auto-generated methods
public record Point(int x, int y) { }
// Equivalent to:
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() { return x; }
public int y() { return y; }
public boolean equals(Object o) { ... }
public int hashCode() { ... }
public String toString() { ... }
}
// Customization
public record Person(String name, int age) {
// Compact constructor (validation)
public Person {
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
name = name.trim(); // Can modify before assignment
}
// Additional constructor
public Person(String name) {
this(name, 0);
}
// Additional methods
public boolean isAdult() {
return age >= 18;
}
}
Pattern Matching for instanceof (Java 16)
// Before
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Java 16+
if (obj instanceof String s) {
System.out.println(s.length()); // s is already cast
}
// With conditions
if (obj instanceof String s && s.length() > 5) {
System.out.println(s.toUpperCase());
}
Switch Expressions (Java 14)
// Traditional switch statement
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
default:
numLetters = -1;
}
// Switch expression (Java 14+)
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
// With yield for blocks
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> {
System.out.println("Tuesday!");
yield 7;
}
default -> throw new IllegalArgumentException();
};
Text Blocks (Java 15)
// Before
String json = "{\n" +
" \"name\": \"John\",\n" +
" \"age\": 30\n" +
"}";
// Text block (Java 15+)
String json = """
{
"name": "John",
"age": 30
}
""";
// HTML
String html = """
<html>
<body>
<p>Hello, World</p>
</body>
</html>
""";
// SQL
String sql = """
SELECT id, name, email
FROM users
WHERE status = 'active'
ORDER BY name
""";
Java 17 Features (LTS)
Sealed Classes
// Restrict which classes can extend/implement
public sealed class Shape permits Circle, Rectangle, Square { }
public final class Circle extends Shape { } // Must be final
public sealed class Rectangle extends Shape permits Square { } // Or sealed
public non-sealed class Square extends Rectangle { } // Or non-sealed
// Sealed interfaces
public sealed interface Vehicle permits Car, Truck, Motorcycle { }
public final class Car implements Vehicle { }
public final class Truck implements Vehicle { }
public final class Motorcycle implements Vehicle { }
Pattern Matching for switch (Preview in 17, Final in 21)
// Type patterns in switch
Object obj = ...;
String result = switch (obj) {
case Integer i -> "Integer: " + i;
case Long l -> "Long: " + l;
case String s -> "String: " + s;
case null -> "null";
default -> "Unknown";
};
// With guards (when)
String result = switch (obj) {
case String s when s.length() > 5 -> "Long string: " + s;
case String s -> "Short string: " + s;
case Integer i when i > 0 -> "Positive: " + i;
case Integer i -> "Non-positive: " + i;
default -> "Unknown";
};
// Record patterns
record Point(int x, int y) {}
String describe(Object obj) {
return switch (obj) {
case Point(int x, int y) when x == y -> "Diagonal point";
case Point(int x, int y) -> "Point at " + x + ", " + y;
default -> "Not a point";
};
}
Java 21 Features (LTS)
Virtual Threads
// Create virtual thread
Thread vThread = Thread.ofVirtual().start(() -> {
System.out.println("Running in virtual thread");
});
// Virtual thread executor
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
}
// Builder
Thread thread = Thread.ofVirtual()
.name("my-virtual-thread")
.start(() -> doWork());
// Platform (traditional) thread for comparison
Thread platformThread = Thread.ofPlatform()
.name("my-platform-thread")
.start(() -> doWork());
Sequenced Collections
// New interfaces for ordered collections
interface SequencedCollection<E> extends Collection<E> {
SequencedCollection<E> reversed();
void addFirst(E e);
void addLast(E e);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
SequencedSet<E> reversed();
}
interface SequencedMap<K, V> extends Map<K, V> {
SequencedMap<K, V> reversed();
Map.Entry<K, V> firstEntry();
Map.Entry<K, V> lastEntry();
Map.Entry<K, V> pollFirstEntry();
Map.Entry<K, V> pollLastEntry();
V putFirst(K k, V v);
V putLast(K k, V v);
}
// Usage
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
list.getFirst(); // "a"
list.getLast(); // "c"
list.reversed(); // Reversed view
Record Patterns (Final)
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}
// Nested deconstruction
void printRectangle(Object obj) {
if (obj instanceof Rectangle(Point(var x1, var y1), Point(var x2, var y2))) {
System.out.println("Rectangle from (" + x1 + "," + y1 + ") to (" + x2 + "," + y2 + ")");
}
}
// In switch
String describe(Object obj) {
return switch (obj) {
case Rectangle(Point(var x, var y), _) when x == 0 && y == 0 ->
"Rectangle at origin";
case Rectangle(Point p1, Point p2) ->
"Rectangle: " + p1 + " to " + p2;
default -> "Unknown";
};
}
String Templates (Preview in 21)
// String templates (preview feature)
String name = "World";
int value = 42;
// STR template processor
String message = STR."Hello \{name}! The answer is \{value}.";
// Result: "Hello World! The answer is 42."
// FMT template processor (with formatting)
String formatted = FMT."Value: %5d\{value}";
// RAW template processor (returns StringTemplate)
StringTemplate template = RAW."Hello \{name}!";
Feature Summary Table
| Feature |
Java Version |
| Lambdas, Streams, Optional |
8 |
| Method References |
8 |
| Default Methods |
8 |
| Date/Time API |
8 |
| Modules (JPMS) |
9 |
| Collection Factory Methods |
9 |
| Private Interface Methods |
9 |
| var keyword |
10 |
| HTTP Client |
11 |
| String strip(), isBlank() |
11 |
| Switch Expressions |
14 |
| Text Blocks |
15 |
| Records |
16 |
| Pattern Matching instanceof |
16 |
| Sealed Classes |
17 |
| Virtual Threads |
21 |
| Sequenced Collections |
21 |
| Pattern Matching switch |
21 |