Introduction to Legacy Code in Java

For years, Java developers have relied on extensive class hierarchies, multiple type checks using the instanceof operator, and explicit type casting to model data and handle complex conditional structures. This traditional approach not only increases the volume of source code but also introduces latent runtime risks, such as ClassCastException, while severely hindering long-term software maintainability.

With the release of Java 21, the language has matured significantly thanks to stable, high-impact features such as Records and Pattern Matching for switch. These modern tools allow architects and developers to write highly expressive, safe code aligned with Google Java Style standards. Below, we will analyze a real refactoring case from a legacy design to a modern, self-documenting design.

The Problem: Legacy Code with Verbose Checks

Let's consider a typical enterprise application processing network or database operation responses using abstract classes and multiple subclasses along with chained if-else blocks to determine the received response type:

// BEFORE: Verbose and error-prone legacy code public abstract class Response { } public class SuccessResponse extends Response { private final String data; public SuccessResponse(String data) { this.data = data; } public String getData() { return data; } } public class ErrorResponse extends Response { private final String errorCode; public ErrorResponse(String errorCode) { this.errorCode = errorCode; } public String getErrorCode() { return errorCode; } } public class ResponseProcessor { public static String process(Response response) { if (response instanceof SuccessResponse) { SuccessResponse success = (SuccessResponse) response; return "OK: " + success.getData(); } else if (response instanceof ErrorResponse) { ErrorResponse error = (ErrorResponse) response; return "FAIL: " + error.getErrorCode(); } else { throw new IllegalArgumentException("Unknown response type"); } } } 

This traditional pattern presents several drawbacks: it requires writing manual constructors, getters, equals, hashCode, and toString methods, while duplicating unnecessary casting logic inside conditional structures.

The Solution: Records and Pattern Matching in Java 21

We can radically refactor this design using sealed interfaces, Records to model immutable data concisely, and Pattern Matching applied to the switch statement. This combination completely eliminates explicit casting and ensures exhaustiveness of analyzed cases.

// AFTER: Clean, modern, and safe code in Java 21 public sealed interface Response permits Response.Success, Response.Error { record Success(String data) implements Response {} record Error(String errorCode) implements Response {} /** * Processes the response safely using pattern matching. * * @param response the response received from the server * @return a formatted string with the processing result */ static String process(Response response) { return switch (response) { case Success(var data) -> "OK: " + data; case Error(var code) -> "FAIL: " + code; }; } } 

Architectural Advantages and Maintainability

  1. Boilerplate Reduction: Records automatically generate the canonical constructor, accessors, string representations, and equality contracts.
  2. Type Safety (Exhaustiveness): The Java compiler validates that all subtypes of a sealed interface are covered in the switch, preventing runtime errors from forgotten branches.
  3. Extreme Readability: Deconstruction patterns allow direct access to internal record components inside the pattern itself.

Auto-Documentation with Artificial Intelligence (Auto-Doc AI)

Using modern standards like Java 21 drastically facilitates the task of Auto-Doc AI tools. Thanks to the clear semantics of sealed interfaces and records, automated documentation generators can infer precise contracts without requiring redundant annotations. By integrating automatic formatters under the Google Java Style standard, we guarantee that code structure remains uniform across the entire development team, reducing friction in code reviews and elevating the overall quality of the corporate repository.

Try it interactively: Format, validate, and auto-document your java directly in JW Solutions Code Formatter & Auto-Doc AI.
Originally published at jw-solutions.com.