Level Up Your Coding: Essential Java 8 to 21 Features You Need to Master

Anil R
3 min read1 day ago

--

Let’s dive into the journey from Java 8 to Java 21, focusing on key features introduced along the way, with detailed explanations and examples.

Java 8: The Foundation

1. Lambda Expressions

Lambdas brought functional programming to Java, letting you pass behavior as an argument. Reduces boilerplate code for implementing functional interfaces.

import java.util.Arrays;
import java.util.List;

public class LambdaExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println("Hello, " + name));
}
}
Hello, Alice
Hello, Bob
Hello, Charlie

name -> System.out.println(name) is a lambda expression.

It is shorthand for implementing the Consumer functional interface.

2. Streams API

Streams let you process collections declaratively — filtering, mapping, reducing — like a pipeline.

import java.util.Arrays;
import java.util.List;

public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToInt(n -> n * 2)
.sum();
System.out.println("Sum of doubled evens: " + sum);
}
}

3. Functional Interfaces and Default Methods

Interfaces with a single abstract method, enhanced with default and static methods.

@FunctionalInterface
interface Calculator {
int add(int a, int b);

default int subtract(int a, int b) {
return a - b;
}
}

@FunctionalInterface ensures the interface has only one abstract method,

default allows method implementation inside interfaces.

4. Optional Class

A container object that may or may not contain a non-null value.

Optional<String> name = Optional.ofNullable(null);
System.out.println(name.orElse("Default Name"));

Optional.ofNullable() handles null gracefully. orElse() provides a fallback value.

5. New Date and Time API (java.time)

Replaced the old Date and Calendar APIs with more robust and immutable classes.

LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plusDays(7);
System.out.println(nextWeek);

Java 9 (2017): Modularity and More

1. Module System (JEP 261)

Java 9 introduced modules for better encapsulation (via module-info.java). It’s less about code syntax and more about project structure.

// module-info.java
module com.example {
exports com.example.app;
}

// com/example/app/Main.java
package com.example.app;
public class Main {
public static void main(String[] args) {
System.out.println("Modular Java!");
}
}

2. Factory Methods for Collections

Simplified creation of immutable collections. List.of() and Set.of() create immutable collections.

List<String> fruits = List.of("Apple", "Banana", "Cherry");
Set<Integer> numbers = Set.of(1, 2, 3);

3. Enhanced try-with-resources

Improved resource management by supporting effectively final variables.

No need to declare the resource inside the try block.

BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
try (reader) {
System.out.println(reader.readLine());
}

Java 10 (Local Variable Type Inference)

Introduced the var keyword for local variables.var infers the data type at compile-time.

var message = "Hello, Java 10!";
System.out.println(message);

Java 11 (HTTP Client and String Enhancements)

Added a new HTTP client and enhanced String methods

String multiline = "Line1\nLine2\nLine3";
multiline.lines().forEach(System.out::println);

Java 14 (Switch Expressions)

Enhanced switch with expressions and arrow labels.

int day = 2;
String dayType = switch (day) {
case 1, 7 -> "Weekend";
default -> "Weekday";
};

Java 21 (2023, LTS): Modern Java

Now, let’s hit the big Java 21 features, building on everything above.

1. Virtual Threads (JEP 444 — Final)

Unlike Java 8’s heavy platform threads, virtual threads are lightweight, perfect for concurrency.

public class ThreadExample {
public static void main(String[] args) throws InterruptedException {
// Java 8 platform thread
Thread thread8 = new Thread(() -> System.out.println("Platform thread"));
thread8.start();
thread8.join();

// Java 21 virtual thread
Thread thread21 = Thread.ofVirtual().start(() -> System.out.println("Virtual thread"));
thread21.join();
}
}

2. Pattern Matching for Switch (JEP 441 — Final)

This evolves Java 17’s switch, adding type patterns.

public class PatternSwitchExample {
public static void main(String[] args) {
Object obj = "Hello";
// Java 8
String result8;
if (obj instanceof String) {
result8 = "String: " + (String) obj;
} else {
result8 = "Not a string";
}
System.out.println(result8);

// Java 21
String result21 = switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
default -> "Unknown";
};
System.out.println(result21);
}
}

3. Record Patterns (JEP 440 — Final)

Pairs with records (Java 16) to deconstruct them in patterns.

record Person(String name, int age) {}

public class RecordPatternExample {
public static void main(String[] args) {
Object obj = new Person("Alice", 25);
if (obj instanceof Person(String name, int age)) {
System.out.println(name + " is " + age);
}
}
}

4. String Templates (JEP 430 — Preview)

A cleaner way to build strings (enable with — enable-preview).

public class StringTemplateExample {
public static void main(String[] args) {
String name = "Bob";
int age = 30;
// Java 8
String result8 = name + " is " + age + " years old.";
System.out.println(result8);

// Java 21
String result21 = STR."\{name} is \{age} years old.";
System.out.println(result21);
}
}

--

--

Anil R
Anil R

Written by Anil R

Full Stack Developer with 15 years experience.

No responses yet