From Java 8 Stubbornness to Java 21: My Upgrade Journey and New Language Features

The article walks through the author's personal upgrade from Java 8 to Java 21, comparing preview features, pattern‑matching instanceof, switch expressions, text blocks, the new HTTP client, var inference, virtual threads, records, immutable collections, try‑with‑resources improvements and other enhancements, while rating each feature’s practicality.

Shepherd Advanced Notes
Shepherd Advanced Notes
Shepherd Advanced Notes
From Java 8 Stubbornness to Java 21: My Upgrade Journey and New Language Features

Background

Oracle released JDK 8 in 2014, making it the mainstream Java version. Ten years later the platform has reached JDK 24, with JDK 8, 11, 17 and 21 being the long‑term support releases.

Preview Features

Preview features are fully designed and implemented but not permanent; they require compilation and runtime flags javac and java with --enable-preview. This allows the community to try and evaluate new capabilities before they become standard.

Pattern Matching for instanceof

Java 8

if (e instanceof MethodArgumentNotValidException) {
    MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) e;
    BindingResult result = methodArgumentNotValidException.getBindingResult();
    ...
}

Java 21

if (e instanceof MethodArgumentNotValidException methodArgumentNotValidException) {
    BindingResult result = methodArgumentNotValidException.getBindingResult();
    ...
}

The Java 21 version eliminates the explicit cast, making the code shorter and clearer. Introduced in JDK 14 (preview) and standardized in JDK 16. Practical rating: ★★★★★

Switch Expressions

Java 8

String dayType;
switch (day) {
    case 1: case 2: case 3: case 4: case 5:
        dayType = "Weekday"; break;
    case 6: case 7:
        dayType = "Weekend"; break;
    default:
        throw new IllegalArgumentException("Invalid day: " + day);
}

Java 21

String dayType = switch (day) {
    case 1, 2, 3, 4, 5 -> "Weekday";
    case 6, 7 -> "Weekend";
    default -> throw new IllegalArgumentException("Invalid day: " + day);
};

The new form is more compact, returns a value directly and avoids missing break. Introduced in JDK 12 (preview) and standardized in JDK 14. Practical rating: ★★★★★

Pattern‑Matching Switch

Combines instanceof with a switch to handle multiple types.

Java 8

if (obj instanceof Integer) {
    return String.format("int %d", obj);
} else if (obj instanceof Long) {
    return String.format("long %d", obj);
} else if (obj instanceof Double) {
    return String.format("double %f", obj);
} else if (obj instanceof String) {
    return String.format("String %s", obj);
}
return obj.toString();

Java 21

return switch (obj) {
    case Integer i -> String.format("int %d", i);
    case Long l    -> String.format("long %d", l);
    case Double d -> String.format("double %f", d);
    case String s -> String.format("String %s", s);
    case null      -> "null";
    default         -> obj.toString();
};

Pattern‑matching switch reduces boilerplate and handles null gracefully. Introduced in JDK 17 (preview) and standardized in JDK 21. Practical rating: ★★★★

Text Blocks

Multi‑line strings become readable without manual escaping.

Java 8

String jsonStr = "{
" +
    "  \"name\":\"张三\",
" +
    "  \"age\":18
" +
    "}
";

Java 21

String jsonStr = """
    {
        "name":"张三",
        "age":38
    }
""";

Text blocks improve readability for JSON, SQL, HTML, etc. Introduced in JDK 13 (preview) and standardized in JDK 15. Practical rating: ★★★★★

HTTP Client API

Java 8

HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("GET");
try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
    String inputLine;
    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
}

Java 21

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .timeout(Duration.ofSeconds(10))
        .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

The new API is fluent, supports sync/async, and includes built‑in timeout and retry. Standardized in JDK 11. Practical rating: ★★★★

Local‑Variable Type Inference ( var )

Java 8

Map<String, List<Employee>> employeeMap = new HashMap<String, List<Employee>>();
Iterator<Map.Entry<String, List<Employee>>> iterator = employeeMap.entrySet().iterator();

Java 21

var employeeMap = new HashMap<String, List<Employee>>();
var iterator = employeeMap.entrySet().iterator();
var

reduces boilerplate, especially with nested generics. Standardized in JDK 11. Practical rating: ★★★

Virtual Threads

Java 8

ExecutorService executor = Executors.newFixedThreadPool(200); // OS threads limit
Future<String> future = executor.submit(() -> httpClient.get(url));

Java 21

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    Future<String> future = executor.submit(() -> httpClient.get(url));
}

Virtual threads are lightweight, many can share a single OS thread, dramatically improving throughput. Previewed in JDK 19, standardized in JDK 21. Practical rating: ★★★★★

Record Classes

Java 8

public class Employee {
    private final String name;
    private final String department;
    private final int salary;
    // constructors, getters, equals, hashCode, toString → >50 lines of boilerplate
}

Java 21

public record Employee(String name, String department, int salary) {}

Records automatically generate accessor methods and immutable semantics. Previewed in JDK 14, standardized in JDK 16. Practical rating: ★★★

Quick Creation of Immutable Collections

Java 8

List<String> list = Collections.unmodifiableList(Arrays.asList("a", "b"));

Java 21

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);

Factory methods provide concise immutable collections without external libraries. Standardized in JDK 9. Practical rating: ★★★

Try‑With‑Resources Improvements

Java 8

try (FileInputStream fis = new FileInputStream("");
     FileOutputStream fos = new FileOutputStream("")) {
    // ...
} catch (IOException e) {
    e.printStackTrace();
}

Java 21

FileInputStream fis = new FileInputStream("");
FileOutputStream fos = new FileOutputStream("");
// multiple resources separated by semicolon
try (fis; fos) {
    // ...
} catch (IOException e) {
    e.printStackTrace();
}

The new syntax makes multi‑resource handling cleaner. Standardized in JDK 9. Practical rating: ★★★★

Sequenced Collections

Java 21 adds methods to directly access the first and last elements.

Java 8

List<Integer> list = new ArrayList<>();
if (!list.isEmpty()) {
    Integer first = list.get(0);
    Integer last = list.get(list.size() - 1);
}

Java 21

List<Integer> list = new ArrayList<>();
if (!list.isEmpty()) {
    Integer first = list.getFirst();
    Integer last = list.getLast();
}

Introduced in JDK 21. Practical rating: ★★★★

Other New Features (brief)

Interface private methods

Enhancements to String, streams, Optional, Files Precise NullPointerException messages

Sealed classes

Method‑handle based reflection for better performance

Scoped Values (preview) as a superior alternative to ThreadLocal for virtual threads

Conclusion

Each JDK release focuses on developer productivity, performance and maintainability. A major theme is garbage‑collector improvement: G1 became default in JDK 9, ZGC arrived in JDK 11 with sub‑10 ms pauses and support for up to 16 TB heaps. Upgrading to Java 21 therefore brings not only language conveniences but also significant runtime gains.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJava8JDK21VirtualThreadsRecordsNewFeaturesSwitchExpressionsPatternMatching
Shepherd Advanced Notes
Written by

Shepherd Advanced Notes

Dedicated to sharing advanced Java technical insights, daily work snippets, and the power of persistent effort.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.