Java 21 Pattern Matching for Switch – Real-World Guide with Practical Examples

2 min read

Java 21 Pattern Matching for Switch – Real-World Guide with Practical Examples

Java 21 Pattern Matching for Switch – Real-World Guide with Practical Examples

1. Introduction

Java 21 brings powerful language improvements, and one of the most impactful is Pattern Matching for switch. This feature allows developers to write more expressive, readable, and safer code when working with complex object hierarchies and type checks. Instead of manual casting and verbose conditional logic, switch can now intelligently match types, extract values, and apply guard conditions directly in each case.

2. Problem

Before Java 21, handling polymorphic objects required repetitive and error-prone code such as multiple instanceof checks, manual type casting, nested if-else blocks, and increased risk of ClassCastException. For real-world applications like payment processing, event handling, or API request parsing, this led to code that was hard to maintain, difficult to read, and fragile when adding new types.

3. Solution

Pattern Matching for switch solves these problems by enabling type-based case matching, variable binding inside switch cases, guarded conditions using when, and cleaner, more declarative control flow. Developers can now process different object types in a structured switch expression without explicit casting.

4. Implementation

Real-Life Scenario: E-Commerce Order Payment Processing

Imagine an e-commerce system that supports multiple payment methods such as Credit Cards, PayPal, and Bank Transfers. Each payment type has different validation rules and transaction fees.

Domain Model

// Base type
sealed interface PaymentMethod permits CreditCard, PayPal, BankTransfer {}

// Implementations
record CreditCard(String cardNumber, String cardHolder, String cvv) implements PaymentMethod {}
record PayPal(String email) implements PaymentMethod {}
record BankTransfer(String accountNumber, String bankCode) implements PaymentMethod {}

Old Way (Pre–Java 21)

public double calculateFeeOld(PaymentMethod payment) {
    if (payment instanceof CreditCard) {
        CreditCard cc = (CreditCard) payment;
        return 2.5;
    } else if (payment instanceof PayPal) {
        PayPal pp = (PayPal) payment;
        return 3.0;
    } else if (payment instanceof BankTransfer) {
        BankTransfer bt = (BankTransfer) payment;
        return 1.0;
    }
    throw new IllegalArgumentException("Unsupported payment type");
}

Java 21 Pattern Matching for switch (Recommended Approach)

public double calculateFee(PaymentMethod payment) {
    return switch (payment) {
        case CreditCard cc -> {
            validateCard(cc);
            yield 2.5;
        }
        case PayPal pp -> {
            validatePayPal(pp);
            yield 3.0;
        }
        case BankTransfer bt -> {
            validateBankTransfer(bt);
            yield 1.0;
        }
    };
}

Using Guarded Patterns

record CreditCard(String cardNumber, String cardHolder, String cvv, boolean corporate) implements PaymentMethod {}

public double calculateFeeWithGuards(PaymentMethod payment) {
    return switch (payment) {
        case CreditCard cc when cc.corporate() -> 1.5;
        case CreditCard cc -> 2.5;
        case PayPal pp -> 3.0;
        case BankTransfer bt -> 1.0;
    };
}

Validation Methods

private void validateCard(CreditCard cc) {
    if (cc.cardNumber().length() != 16) {
        throw new IllegalArgumentException("Invalid card number");
    }
}

private void validatePayPal(PayPal pp) {
    if (!pp.email().contains("@")) {
        throw new IllegalArgumentException("Invalid PayPal email");
    }
}

private void validateBankTransfer(BankTransfer bt) {
    if (bt.accountNumber().isBlank()) {
        throw new IllegalArgumentException("Invalid bank account number");
    }
}

Benefits Demonstrated: Eliminates manual casting, improves readability, reduces runtime errors, and makes it easier to extend with new payment types.

5. Conclusion

Pattern Matching for switch in Java 21 significantly modernizes how developers handle polymorphism and conditional logic. By enabling type-safe matching, variable binding, and guards directly in the switch construct, Java becomes more concise, maintainable, and expressive. For real-world systems such as payment platforms, this feature simplifies complex business logic and makes future enhancements far easier to implement.

🤞 Never miss a story from us, get weekly updates to your inbox!

Leave a Reply

Your email address will not be published. Required fields are marked *