DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Top Java Security Vulnerabilities and How to Prevent Them in Modern Java
  • Multithreading in Modern Java: Advanced Benefits and Best Practices
  • Apache Spark 3 to Apache Spark 4 Migration: What Breaks, What Improves, What's Mandatory
  • Memory Optimization and Utilization in Java 25 LTS: Practical Best Practices

Trending

  • Stop Choosing Sides: An Engineering Leader's Framework for Build, Buy, and Hybrid AI Agents in 2026
  • AI Is Finding Bugs Faster Than Enterprises Can Patch — Here's What Data Security Teams Should Do
  • Stateless JWT Auth Microservice Architecture With Spring Boot 3 and Redis Sentinel
  • Run Gemma 4 on Your Laptop: A Hands-On Guide to Google's Latest Open Multimodal LLM
  1. DZone
  2. Coding
  3. Java
  4. From printTriangularNumber to Duff’s Device: Mastering Java Switch Statements Old and New

From printTriangularNumber to Duff’s Device: Mastering Java Switch Statements Old and New

This post traces that journey using triangular number computation as a practical example of intentional fall-through and connects the technique to Duff's Device.

By 
NaveenKumar Namachivayam user avatar
NaveenKumar Namachivayam
DZone Core CORE ·
Jun. 19, 26 · Analysis
Likes (1)
Comment
Save
Tweet
Share
187 Views

Join the DZone community and get the full member experience.

Join For Free

In this blog post, we will see how the humble Java switch statement evolved from a fall-through curiosity into a powerful expression, and how understanding its mechanics unlocks classic techniques like Duff's Device.

Java's switch statement has evolved from a fall-through-prone construct into a modern expression syntax introduced in Java 14. The post traces this evolution using a concrete example, a method that computes triangular numbers by intentionally allowing execution to cascade through cases without break statements.

The post also connects this behavior to Duff's Device, a 1983 loop-unrolling technique that uses deliberate fall-through to handle remainder elements before processing full blocks. A comparison of old and new switch syntax outlines trade-offs, and practical guidance is offered on when each form is appropriate.

The Accidental Discovery

I was prepping for the OCP Java 21 exam and stumbled across a tricky question. A method named question2 used a switch statement without any break statements. The output surprised me at first.

Once I traced through it, I renamed the method to printTriangularNumber. That one rename told the whole story. This post dives into why.

The Old Switch Statement

The traditional switch statement has been part of Java since day one. The syntax looks like this:

Java
 
int day = 3;
switch (day) {
    case 1:
        System.out.println("Monday");
        break;
    case 2:
        System.out.println("Tuesday");
        break;
    case 3:
        System.out.println("Wednesday");
        break;
    default:
        System.out.println("Unknown");
        break;
}


As shown above, every case ends with a break. Without it, execution does not stop. It keeps going into the next case.

The old switch works on int, char, String, and enum types.

Fall-Through: Feature or Bug?

The most misunderstood behavior in switch is fall-through. When you omit break, execution literally falls into the next case.

Java
 
int x = 2;
switch (x) {
    case 3: System.out.println("three");
    case 2: System.out.println("two");   // jumps here
    case 1: System.out.println("one");   // falls through
    default: System.out.println("done"); // falls through
}


Output:

Plain Text
 
two
one
done


Most developers treat this as a bug waiting to happen. They are not wrong. Forgetting a break is one of the most common Java mistakes. But intentional fall-through is a different story. It is a deliberate tool. And printTriangularNumber is the perfect example.

printTriangularNumber: Fall-Through in Action

Here is the method I renamed from question2 during my OCP prep:

Java
 
private static void printTriangularNumber(int n) {
    int res = 0;
    switch (n) {
        case 5:
            res += 5;
        case 4:
            res += 4;
        case 3:
            res += 3;
        case 2:
            res += 2;
        case 1:
            res += 1;
        default:
            break;
    }

    System.out.println(res == 0 ? "Ok, bye." : res);


Let us trace through n = 4:

  1. Jumps to case 4, adds 4. res = 4
  2. Falls to case 3, adds 3. res = 7
  3. Falls to case 2, adds 2. res = 9
  4. Falls to case 1, adds 1. res = 10
  5. Hits default, breaks

Output: 10

The pattern for each input:

n Result Formula
1 1 1
2 3 2+1
3 6 3+2+1
4 10 4+3+2+1
5 15 5+4+3+2+1


This is n * (n + 1) / 2, the triangular number formula. The fall-through is doing the summation for you. Each case accumulates the remaining values by simply not stopping.

For n = 0 or any value above 5, no case matches, default fires immediately, and res stays 0. The ternary prints "Ok, bye.".

I personally find it a beautiful example of using language semantics intentionally. This is also the kind of question the OCP exam loves to throw at you.

The New Switch Expression (Java 14+)

Java 14 introduced switch expressions as a standard feature. The arrow syntax -> eliminates fall-through entirely. Each arm is independent.

Java
 
int day = 3;
String name = switch (day) {
    case 1 -> "Monday";
    case 2 -> "Tuesday";
    case 3 -> "Wednesday";
    default -> "Unknown";
};
System.out.println(name); // Wednesday


A few things to notice here:

  • Switch is now an expression. It returns a value.
  • The arrow -> replaces : and break together.
  • No fall-through. Each arm executes independently.
  • Multiple labels on a single arm: case 1, 7 -> "Weekend";

You can also use it inline:

Java
 
System.out.println(switch (day) {
    case 1, 7 -> "Weekend";
    default   -> "Weekday";
});


Much cleaner. Much safer.

Switch Expressions With Yield

Sometimes you need more than a single expression in an arm. That is where yield comes in.

Java
 
int n = 4;
int result = switch (n) {
    case 1, 2 -> n * 10;
    case 3, 4 -> {
        int temp = n * n;
        System.out.println("Computing for: " + n);
        yield temp; // return value from block
    }
    default -> 0;
};
System.out.println(result); // 16


Think of yield as the return statement for a switch block arm. You need it whenever the arm has multiple statements inside {}.

A common mistake is using return instead of yield inside a switch expression block. That compiles only inside a method and it returns from the entire method, not just the switch. Always use yield inside switch expression blocks.

Duff's Device: Fall-Through Taken to the Extreme

Now that we understand fall-through well, let us look at the most famous intentional use of it: Duff's Device.

Tom Duff invented this in 1983 to speed up memory copy operations by reducing loop branch overhead. The trick is to unroll the copy loop and use a switch to jump into the middle of it based on the remainder.

In Java, we replicate it in two clean phases since Java does not allow interleaved switch+loop syntax:

Java
 
public static void duffCopy(int[] src, int[] dst, int n) {
    int i = 0;
    int rem = n % 4;

    // Phase 1: handle remainder via fall-through
    switch (rem) {
        case 3: dst[i] = src[i]; i++;
        case 2: dst[i] = src[i]; i++;
        case 1: dst[i] = src[i]; i++;
        case 0: break;
    }

    // Phase 2: full blocks of 4
    int fullBlocks = (n - rem) / 4;
    while (fullBlocks-- > 0) {
        dst[i] = src[i]; i++;
        dst[i] = src[i]; i++;
        dst[i] = src[i]; i++;
        dst[i] = src[i]; i++;
    }
}


Let us trace through n = 13:

  1. rem = 13 % 4 = 1
  2. Switch jumps to case 1, copies 1 element. i = 1
  3. fullBlocks = (13 - 1) / 4 = 3
  4. Loop runs 3 times, copying 4 elements each time
  5. Total: 1 + 12 = 13 elements

The Python equivalent makes the two phases explicit:

Python
 
def duff_copy(src, n):
    dst = [None] * n
    rem = n % 4

    for i in range(rem):        # Phase 1: remainder
        dst[i] = src[i]

    i = rem
    while i < n:                # Phase 2: full blocks
        dst[i]   = src[i]
        dst[i+1] = src[i+1]
        dst[i+2] = src[i+2]
        dst[i+3] = src[i+3]
        i += 4

    return dst


The connection to printTriangularNumber is direct. Both use fall-through intentionally. In printTriangularNumber, the switch jumps to the right case and accumulates downward. In Duff's Device, the switch jumps to the right case and copies the remainder before the main loop takes over.

Old vs. New Switch at a Glance

Feature Old Switch (:) New Switch (->)
Fall-through Yes (default) No
Returns value No Yes
break needed Yes No
Multiple labels No Yes (case 1, 2 ->)
Block with yield No Yes
Null safe No Yes (Java 21 preview)
OCP exam topic Yes Yes


Which One Should You Use?

For new code, always prefer the switch expression with ->. It is safer, cleaner, and expressive. Your reviewers will thank you.

Reserve the old switch with fall-through only when you genuinely need the cascading behavior, like in printTriangularNumber or a hand-tuned loop like Duff's Device. In those cases, add a comment explaining the intent. Otherwise, the next developer (including future you) will assume the break is missing by accident.

My personal observation: the OCP Java 21 exam tests both heavily. Knowing when fall-through is intentional versus accidental is the key distinction examiners probe. Make sure you can trace through any switch block without running it.

Happy testing!

What is your take: is intentional fall-through clever engineering or a maintenance nightmare waiting to happen? Drop your thoughts below!

Java (programming language) Data Types

Published at DZone with permission of NaveenKumar Namachivayam. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Top Java Security Vulnerabilities and How to Prevent Them in Modern Java
  • Multithreading in Modern Java: Advanced Benefits and Best Practices
  • Apache Spark 3 to Apache Spark 4 Migration: What Breaks, What Improves, What's Mandatory
  • Memory Optimization and Utilization in Java 25 LTS: Practical Best Practices

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook