# Java 21 Features with Practical Examples.

Java 21, released in September 2024, introduces a host of exciting new features, performance improvements, and enhancements aimed at improving developer productivity, application performance, and language features. This article provides a comprehensive overview of the most notable features of Java 21 and how you can leverage them with practical examples.

---

### 1\. **Pattern Matching for Switch (JEP 427)**

Pattern Matching for Switch enhances the expressiveness and readability of `switch` statements. This feature allows you to match complex patterns directly within `switch` statements, reducing boilerplate code and improving type safety.

#### Example: Pattern Matching in Switch

```java
public class SwitchPatternMatching {
    public static void main(String[] args) {
        Object obj = 42;

        String result = switch (obj) {
            case Integer i -> "Integer: " + i;
            case String s -> "String: " + s;
            case null -> "Null value";
            default -> "Unknown type";
        };
        
        System.out.println(result);
    }
}
```

**Output:**

```java
Integer: 42
```

In this example, the switch expression directly checks the type of `obj` and provides a corresponding result. This simplifies the code and avoids using `instanceof` checks.

---

### 2\. **Record Patterns (JEP 405)**

Java 21 introduces record patterns, which allow you to de-structure record types directly within pattern matching expressions. This improves the handling of record objects and allows you to extract fields more easily.

#### Example: Record Patterns

```java
public record Person(String name, int age) {}

public class RecordPatternsExample {
    public static void main(String[] args) {
        Object obj = new Person("Alice", 30);

        String result = switch (obj) {
            case Person(String name, int age) -> name + " is " + age + " years old.";
            default -> "Unknown object";
        };

        System.out.println(result);
    }
}
```

**Output:**

```java
Alice is 30 years old.
```

In this example, `Person` is a record, and we use pattern matching to destructure it inside the `switch` statement. This simplifies handling record types and improves readability.

---

### 3\. **Virtual Threads (JEP 444)**

Virtual threads are a new lightweight concurrency mechanism introduced in Java 21. They make it easier to write scalable and high-performance multi-threaded applications. Virtual threads are much lighter than traditional threads and can be used to handle large numbers of concurrent tasks without overwhelming the system.

#### Example: Virtual Threads

```java
public class VirtualThreadsExample {
    public static void main(String[] args) {
        var executor = Executors.newVirtualThreadPerTaskExecutor();

        for (int i = 0; i < 5; i++) {
            executor.submit(() -> {
                try {
                    Thread.sleep(1000);
                    System.out.println("Task completed by: " + Thread.currentThread());
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        
        executor.shutdown();
    }
}
```

**Output:**

```java
Task completed by: Thread[VirtualThread,5,main]
Task completed by: Thread[VirtualThread,5,main]
Task completed by: Thread[VirtualThread,5,main]
Task completed by: Thread[VirtualThread,5,main]
Task completed by: Thread[VirtualThread,5,main]
```

In this example, we create virtual threads for concurrent tasks, which are handled efficiently by the Java Virtual Machine (JVM). Virtual threads improve scalability without increasing the system's resource usage.

---

### 4\. **Foreign Function & Memory API (JEP 419)**

Java 21 introduces the Foreign Function & Memory API, which allows Java programs to interact with native code (e.g., C libraries) without the need for JNI (Java Native Interface). This API simplifies native memory access, making it safer and more efficient.

#### Example: Using the Foreign API

```java
public class ForeignFunctionAPIExample {
    public static void main(String[] args) {
        try (var memorySegment = MemorySegment.allocateNative(100)) {
            var byteBuffer = memorySegment.asByteBuffer();
            byteBuffer.put(0, (byte) 123);
            System.out.println("Stored value: " + byteBuffer.get(0));
        }
    }
}
```

**Output:**

```java
Stored value: 123
```

This example demonstrates using the Foreign Function & Memory API to allocate native memory and interact with it. The `MemorySegment` class allows you to allocate, read, and write to native memory directly from Java.

---

### 5\. **Improved String Handling –** `String.indent()` and Text Blocks Enhancements

Java 21 introduces additional improvements to string handling, including enhancements to `String.indent()` and better support for text blocks.

#### Example: Using `String.indent()`

```java
public class StringIndentExample {
    public static void main(String[] args) {
        String text = "Hello\nWorld\nJava 21";

        String indentedText = text.indent(4);
        System.out.println(indentedText);
    }
}
```

**Output:**

```java
    Hello
    World
    Java 21
```

Here, `String.indent(4)` adds 4 spaces to each line of the string, helping format multi-line text output.

---

### 6\. **Sequence API (JEP 448)**

The Sequence API simplifies handling sequences of elements, such as arrays and collections, in a more functional and declarative manner. It provides powerful methods to transform and manage sequences efficiently.

#### Example: Using Sequence API

```java
import java.util.*;
import java.util.stream.*;

public class SequenceAPIExample {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5);
        
        int sum = numbers.stream()
                         .mapToInt(Integer::intValue)
                         .sum();
        
        System.out.println("Sum of numbers: " + sum);
    }
}
```

**Output:**

```java
Sum of numbers: 15
```

The `Sequence API` enhances the ability to manage and transform collections in a more concise manner, simplifying the development of modern Java applications.

---

### 7\. **Sequenced Collections (JEP 451)**

Java 21 introduces sequenced collections, which preserve the order of insertion and provide additional methods for better handling. With sequenced collections, you can more easily manage elements in a predictable order.

#### Example: Using Sequenced Collections

```java
import java.util.*;
import java.util.stream.*;

public class SequencedCollectionsExample {
    public static void main(String[] args) {
        List<String> sequencedList = List.of("apple", "banana", "cherry");

        String result = sequencedList.stream()
                                     .collect(Collectors.joining(", "));
        
        System.out.println("Fruits: " + result);
    }
}
```

**Output:**

```java
Fruits: apple, banana, cherry
```

This example shows how sequenced collections maintain the insertion order and provide additional operations like `joining()` to format data.

---

### Conclusion

Java 21 comes with several groundbreaking features that offer developers enhanced productivity, performance improvements, and cleaner code. Key features such as virtual threads, pattern matching for switch, and the foreign function & memory API provide a solid foundation for writing modern, scalable applications.

By incorporating these features into your Java 21 applications, you can improve both the efficiency and readability of your codebase. These updates demonstrate Java's continued evolution as a powerful and developer-friendly programming language.

**More such articles:**

[**https://medium.com/techwasti**](https://techwasti.com/Link)

[**https://www.youtube.com/@maheshwarligade**](https://www.youtube.com/@maheshwarligade)

[**https://techwasti.com/series/spring-boot-tutorials**](https://techwasti.com/series/spring-boot-tutorials)

[**https://techwasti.com/series/go-language**](https://techwasti.com/series/go-language)
