Java continues to evolve, releasing new features in each version. In Java 24, we’ve seen the consolidation of several previews introduced in previous versions: more powerful primitive patterns and a continued push toward modern, clean, and powerful code.

If you're still using Java 8, 11, or even Java 17 and haven’t moved to 21 yet, it’s time to upgrade before the leap becomes too great.

What’s New in Java 24

It’s important to remember that some of the features we’re discussing are still in preview. This means you’ll need to enable them using the –enable-preview flag for the Java 24 compiler to recognize them.

1 Primitive Patterns (preview): primitives deserve love too (JEP 488)

Java 24 moves forward with primitive patterns, delivering a second preview (you can read about the first preview here and the updates in this second preview). It expands the capabilities of instanceof and switch by enabling pattern matching with primitive types, such as int, boolean, and double, without the need to convert them to Integer or Double.

How does this look in code? Previously, you'd write something like:

Object o = 42;

if (o instanceof Integer i && i > 10) {
    System.out.println("Whole number greater than 10");
}

Now, in Java 24, we can perform that comparison directly using the primitive type:

Object o = 42;

if (o instanceof int i && i > 10) {
    System.out.println("Primitive integer greater than 10");
}

2 Stream Gatherers: Streams, assemble! JEP 485

JEP 485

Streams and Java have gone hand in hand since Java 8, and Java 24 is no exception. With the (now final) implementation of the Gatherers API, Java 24 enables more advanced operations than those offered by Collectors, such as custom groupings, sliding windows, or batching. Let’s illustrate this with an example:

Stream.of(1, 2, 3, 4, 5, 6)
    .gather(Gatherers.windowFixed(3))
    .forEach(System.out::println);
[1, 2, 3], [4, 5, 6]

A new gather method is introduced, coming from the java.util.stream.Gatherer interface. It provides a set of methods that we’ll be able to use in future implementations as intermediate operations within the stream pipeline:

import java.util.stream.Stream;
import java.util.stream.Gatherers;

Stream.of(1, 2, 3, 4)
    .gather(Gatherers.scan(0, Integer::sum))
    .forEach(System.out::println);

The output would be as follows:

1
3
6
10
import java.util.stream.Stream;
import java.util.stream.Gatherers;

Stream.of("Java", "24", "es", "potente")
      .gather(Gatherers.fold(
          "",                              // seed
          (acc, s) -> acc.isEmpty() ? s : acc + " - " + s,  // accumulator
          (a, b) -> a + " - " + b           // parallel merge combinator
      ))
      .forEach(System.out::println);

The output would be as follows:

Java - 24 - is - powerful

These are some of the most important methods from the library, but they are not the only ones available. Since we are still in preview versions, it’s important to get familiar with them gradually. That’s why we invite you to experiment and take a look directly at the official Java 24 documentation.

4 Scoped Values (preview). A modern replacement for ThreadLocal. JEP487

JEP 487

As the fourth preview, Java 24 continues advancing with Scoped Values — a new, safer, immutable, and lightweight way to pass data across virtual threads.

In previous versions, these threads could be modified — that is, they lacked immutability, could lead to memory leaks, and didn’t always offer optimal performance. Here's an example of how it used to be and how it evolves:

ThreadLocal<String> userId = new ThreadLocal<>();
userId.set("abc-123");
//It must be cleaned (removed) manually, which ends up being dangerous.

Now with Java 24, we will have the following:

ScopedValue<String> USER_ID = ScopedValue.newInstance();

ScopedValue.where(USER_ID, "abc-123").run(() -> {
    System.out.println("Current user: " + USER_ID.get());
});

We can see that now the value is immutable, which provides greater safety and is automatically scoped, without needing to call .remove() as we had to do before to free up memory.

This improvement can be helpful to pass information like user ID, session tokens, request configuration, etc. But remember, it is still a preview feature (don’t forget: –enable-preview to make it work).

4 Other changes: it’s not all about coding

Java 24 also brings other enhancements and updates beyond programming style. Some of the most noteworthy are:

5 Java 24 embraces transformation

It’s evident that, starting from a few versions ago (especially from Java 14), Java is moving towards a more declarative, safer, and expressive programming model, evolving into a more modern language — all while staying true to its roots.

As developers, we can’t really complain. Java continues to evolve and adapt to modern development practices, paving the way for Java 25 and beyond in terms of style, clean coding practices, and—most importantly in today’s world—code security. We’ll keep a close eye on upcoming updates and news about future Java releases. What does the future hold?

References

Tell us what you think.

Comments are moderated and will only be visible if they add to the discussion in a constructive way. If you disagree with a point, please, be polite.

Subscribe