Skip to content

Java New Features since Java 8

Java Version Timeline

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