Tagged “backend”

  1. Project Loom: Java's Virtual Threads – From Nightmares to Modern Concurrency Bliss

    ~ cat post <<

    Project Loom: Java's Virtual Threads

    In 2006, I worked on a large logistics system for transporting wood for pulp production. One of the most critical modules managed the entry and exit of trucks from a storage yard. We implemented it using Threads in Delphi 7. The debugging process was an absolute nightmare.

    Hundreds of trucks arriving and leaving, each one triggering database checks, sensor readings, queue management, and synchronization logic. Every thread was a heavyweight OS thread. Memory usage skyrocketed, context switching killed performance, and when something went wrong (which happened constantly), the debugger would freeze or show you a stack trace that made zero sense because the threads were all fighting for the same resources.

    Sound familiar?

    That exact pain — the same pain Java developers have felt for 30 years with regular Thread objects and ExecutorService backed by platform threads — is what Project Loom was created to eliminate.

    Today, with Java 21+ (and fully mature in 2026), Virtual Threads are production-ready and change the game completely.

    Let’s demystify Project Loom and see, with real Java code, why Virtual Threads are not just “better threads” — they are a completely different beast.

    The Problem with Traditional (Platform) Threads

    Since Java 1.0, every new Thread() or thread from a ThreadPoolExecutor is a platform thread:

    • It maps one-to-one to an OS thread.
    • It consumes ~1 MB of stack space (configurable, but rarely less).
    • Creating thousands of them is expensive and risky.
    • Blocking operations (I/O, sleep(), database calls, HTTP requests) block the entire OS thread.
    • Context switching is handled by the operating system (expensive).

    In the 2006 Delphi system, we could barely handle a few hundred concurrent trucks before the server started thrashing. The same limitation existed in Java until Project Loom.

  2. Java 26: Pattern Matching Finally Reaches Primitive Types

    ~ cat post <<

    Java 26 Primitive Pattern Matching

    Java has been evolving pattern matching for a while now. We got it for instanceof, then for switch, then for records. Each release pushed the idea a bit further. But there was always an odd limitation:

    Pattern matching worked great — as long as you stayed in the world of objects.

    Primitive types? Not invited.

    With Java 23, that gap is finally gone (as the first preview of this feature). This isn’t a flashy feature. It won’t generate “Java is reinvented” thumbnails. But it fixes something that has felt slightly off for years. In Java 26 we have the fourth preview of this feature, and it something that worth talking about.

    Let’s take a look at what changed — and why it actually matters.

    The Awkward Gap in Pattern Matching

    Before Java 23, pattern matching was strictly tied to reference types.

    Object value = 10;
    
    if (value instanceof Integer i) {
        System.out.println(i + 1);
    }
    

    This works. But it comes with baggage:

  3. Java 25 After the Hype: 5 Features That Actually Matter

    ~ cat post <<

    Java 25 After the Hype: 5 Features That Actually Matter

    When a new Java version drops, the internet goes through its usual cycle: launch posts, conference talks, YouTube thumbnails screaming “GAME CHANGER,” and LinkedIn hot takes about how everything has changed forever.

    Then reality settles in.

    A few months after the release of Java 25, most teams aren’t rewriting their systems. They’re shipping features, fixing bugs, and trying to keep production stable. That’s when we can finally answer a more interesting question:

    Which Java 25 features are still being discussed and actually used?

    This isn’t a launch recap. This is a “post-hype” filter. Here are five Java 25 features that have proven they’re more than marketing bullets.

    1. Structured Concurrency: Concurrency That Reads Like Logic (preview)

    For years, Java concurrency meant juggling ExecutorService, Future, timeouts, and cancellation semantics that were easy to get wrong.

    Structured Concurrency changes the mental model. Instead of spawning detached tasks and hoping everything is cleaned up properly, you treat concurrent tasks as a single logical unit.

    Before

    ExecutorService executor = Executors.newFixedThreadPool(2);
    
    Future<User> userFuture = executor.submit(() -> fetchUser());
    Future<Orders> ordersFuture = executor.submit(() -> fetchOrders());
    
    User user = userFuture.get();
    Orders orders = ordersFuture.get();
    
  4. Spring Boot 4: Brief Upgrade Guide and Code Comparison

    ~ cat post <<

    Spring Boot 4 vs. 3: Brief Upgrade Guide and Code Comparison

    If you’ve been following my blog, you know I love a good migration story. Whether it’s moving to TanStack Start or refining shadcn/ui forms, the goal is always the same: better developer experience and more robust code.

    Today, we’re looking at the big one. Spring Boot 4.0 is officially out, and it’s arguably the most important release since 3.0. It moves the baseline to &Java 17 (with a massive push for Java 25), adopts Jakarta EE 11, and introduces features that finally kill off years of boilerplate.

    Let’s look at exactly what changed and how your code will look before and after the upgrade.

    1. Native API Versioning

    For years, versioning an API in Spring meant custom URL paths, header filters, or complex RequestCondition hacks. Spring Boot 4 brings this into the core framework.

    The Spring Boot 3 Way (Manual Pathing)

    // You had to manually manage the path segments
    @RestController
    @RequestMapping("/api/v1/orders")
    public class OrderControllerV1 { ... }
    
    @RestController
    @RequestMapping("/api/v2/orders")
    public class OrderControllerV2 { ... }
    

    The Spring Boot 4 Way (Native Mapping)

    Now, versioning is a first-class citizen. You can keep the path clean and let Spring handle the routing logic via headers, query params, or path segments.

~ <<

See all tags .