Hidden Gems: The Most Underutilized Features in Java 21-23 Editorial Team, January 11, 2026January 11, 2026 The arrival of new Java versions, especially the rapid cadence since the shift to LTS every two years, brings a flood of headlines. We rightly celebrate the big-ticket items: record patterns, virtual threads, sequenced collections. But in the shadow of these giants lie subtle, elegantly designed features that often go unnoticed. These underutilized gems, from Java 21 through 23, offer profound improvements to code clarity, maintainability, and expressiveness with minimal ceremony. Let’s excavate these hidden treasures. Table of Contents Toggle Java 21’s Quiet Revolution: Unnamed Patterns and VariablesThe Secret Power of Sequenced CollectionsJava 22’s Stream Supercharger: GatherersString Templates: Beyond String Interpolation (Java 21 Preview, Refined in 22/23)Implicitly Declared Classes and Instance Main Methods (Java 21, Refined)The ScopedValue Replacement for ThreadLocal (Java 21, Incubator)Conclusion: The Depth Beneath the Headlines Java 21’s Quiet Revolution: Unnamed Patterns and Variables While pattern matching for instanceof and switch grabs attention, its companion feature, Unnamed Patterns and Variables, is a masterpiece of simplicity. How often do you write a pattern where you must bind a variable you will never use? The classic example is navigating a complex object. Before: if (obj instanceof Point(Point inner, int x)) { // Need 'inner' for structure, but only use 'x' System.out.println(x); } With an unnamed pattern (using _), you explicitly denote irrelevance: if (obj instanceof Point(_, int x)) { System.out.println(x); } More powerfully, unnamed variables (_) work in catch blocks, try-with-resources, and loops, eliminating cognitive noise. try (var _ = acquireResource()) { // We don't need to name it doWork(); } for (int i = 0, _ = sideEffectInit(); i < 10; i++) { // Ignore the side-effect result // loop body } This isn’t just shorter code; it’s communicative code. It tells the reader, “This value is structurally necessary but semantically unimportant.” It’s a declaration of intent. See also Full-Stack Java with HTMX and Thymeleaf: A Modern ApproachThe Secret Power of Sequenced Collections Java 21’s Sequenced Collections interface (SequencedCollection, SequencedSet, SequencedMap) brought a long-missing order to the collection hierarchy. The headline methods are getFirst(), getLast(), addFirst, and addLast. But the hidden gem is the reversed() method. This method returns a view of the collection in reverse order. It’s lazy, constant-time, and affects any changes made to the underlying collection. This trivializes tasks that were previously clunky: SequencedCollection<String> list = new ArrayList<>(List.of("a", "b", "c")); // Iterate backwards cleanly for (String s : list.reversed()) { System.out.println(s); // c, b, a } // Need the last three elements in insertion order? list.reversed().stream().limit(3).toList(); It turns algorithmic thinking on its head for many common operations, providing an elegant, performance-safe tool directly in the interface. Java 22’s Stream Supercharger: Gatherers Virtual threads were the rockstar of Java 21. Still, Java 22 introduced a feature for library designers and power users that might have a more lasting impact on daily code: the Gatherer interface (preview). We’ve lived with Stream.collect(Collector) for terminal operations and intermediate operations like filter, map, and limit. But what about custom, stateful, intermediate operations? Previously, you had to hack it with flatMap or use a terminal collector, breaking the stream. Gatherers unlock this. They allow you to build custom, reusable intermediate operations. The JDK itself provides built-in gatherers like windowFixed and fold. Imagine implementing a “stateful filter” that only passes elements that are different from the previous one (dedupe consecutive): List<String> letters = List.of("a", "a", "b", "a", "c", "c"); List<String> result = letters.stream() .gather(Gatherers.deduplicateConsecutive()) .toList(); // ["a", "b", "a", "c"] You can build gatherers for running averages, batching, throttling, or complex state machines—all as reusable, composable stream steps. It’s a foundational shift in stream capabilities that most are yet to discover. See also The 2026 Java Developer's Toolbox: Essential VS Code & IntelliJ PluginsString Templates: Beyond String Interpolation (Java 21 Preview, Refined in 22/23) String Templates are often mistaken for “just” string interpolation. They are far more. The hidden gem is the template processor. Yes, the STR processor is the obvious one for interpolation: String name = "Java"; String message = STR."Hello, \{name}!"; // "Hello, Java!" But the power lies in FMT for formatting and, crucially, in defining your own processors. A template processor can validate, sanitize, or transform the template before it is converted into a string. Think of SQL. Instead of fragile concatenation, imagine: String query = SQL.""" SELECT * FROM Employee WHERE dept = \{deptId} AND status = \{status} """; A custom SQL processor could validate the deptId and status against injection attacks, or even prepare a PreparedStatement directly, returning an object, not a string. The same could apply to JSON, HTML, or shell commands, turning runtime syntax errors into compile-time safety. This paradigm shift from simple interpolation to safe, structured composition is profoundly underutilized. Implicitly Declared Classes and Instance Main Methods (Java 21, Refined) Designed for beginners, this feature is a hidden gem for scripting, prototyping, and microservices. The ability to write: void main() { System.out.println("Hello, World!"); } without the enclosing class and public static void main(String[] args) ceremony is liberating for quick tests, educational snippets, or even small HTTP endpoints (with a framework). It lowers the barrier to writing a single-file Java program to the level of Python or JavaScript, making Java a more viable tool for tasks far outside its traditional enterprise domain. The ScopedValue Replacement for ThreadLocal (Java 21, Incubator) Overshadowed by virtual threads ScopedValue is a revolutionary concurrency construct. It addresses the downsides of ThreadLocal (unbounded memory retention, expensive inheritance) in structured concurrency environments. See also Project Leyden Checkpoint: Solving Java’s Slow Startup in 2026A ScopedValue allows an immutable value to be safely and efficiently shared for the dynamic scope of a method and all its callees, especially across virtual threads. It’s a perfect fit for passing contextual data like user credentials or trace IDs in a server handling millions of virtual threads. final static ScopedValue<User> CURRENT_USER = ScopedValue.newInstance(); ScopedValue.runWhere(CURRENT_USER, authenticatedUser, () -> { handleRequest(); // Any code here can read CURRENT_USER.get() }); // Value is automatically unavailable here, and eligible for GC. It provides thread-locality semantics with structured, predictable lifetimes, a critical tool for modern, virtual-thread-based architectures. Conclusion: The Depth Beneath the Headlines The evolution of Java is not just a story of monolithic features. It’s a story of thoughtful, granular improvements that collectively polish the language to a sheen. These hidden gems—unnamed variables that clarify intent, sequenced views that simplify logic, gatherers that unlock stream expressiveness, template processors that ensure safety, and scoped values that modernize concurrency—represent the maturing philosophy of Java: to be increasingly expressive, safe, and developer-friendly without sacrificing its core tenets of readability and robustness. Exploring these features isn’t about using the newest thing for its own sake. It’s about discovering more precise, communicative, and efficient tools for the problems you already solve. The next time you write Java, look beyond the release notes’ headlines. You might find a hidden gem that transforms a dozen lines of boilerplate into a single, elegant statement. That’s the quiet power of modern Java. Java