DEV Community

Cover image for Java 23: Unnamed Patterns and Variables
MyExamCloud
MyExamCloud

Posted on

Java 23: Unnamed Patterns and Variables

Java 23 introduces unnamed variables and unnamed patterns, which improve code readability and maintainability by allowing developers to omit unused variables and patterns. These features reduce clutter and make it easier to focus on the relevant parts of the code.

Unnamed Variables

Unnamed variables are variables that can be declared but not used. They are useful when the side effect of a statement is more important than the variable itself. These variables are denoted using the underscore character (_).

Example: Using Unnamed Variables in a For Loop

Consider a simple iteration through an array:

String[] names = {"Alice", "Bob", "Charlie", "David"};
int count = 0;
for (String _ : names) {
    count++;
}
System.out.println("Total names: " + count);
Enter fullscreen mode Exit fullscreen mode

Here, _ replaces the unused loop variable, making it clear that the loop only counts the elements.

Valid Declarations of Unnamed Variables

Unnamed variables can be used in several contexts:

  1. Local Variable Declaration:

    record Transaction(String id, double amount) { }
    static List<Transaction> filterTransactions(Queue<Transaction> queue, int limit) {
        var filtered = new ArrayList<Transaction>();
        try {
            while (limit > 0) {
                Transaction _ = queue.remove();
                Transaction _ = queue.remove();
                filtered.add(queue.remove());
                limit--;
            }
        } catch (NoSuchElementException _) {
            // Do nothing
        }
        return filtered;
    }
    
  2. Try-with-Resources Statement:

    static void checkFile(String filePath) {
        try (var _ = new BufferedReader(new FileReader(filePath))) {
            // Do nothing
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
  3. For Loop Header:

    Function<Integer, String> logEffect = n -> {
        System.out.println("Processing: " + n);
        return "Done";
    };
    for (int i = 0, _ = logEffect.apply(100); i < 5; i++) {
        System.out.println("Step: " + i);
    }
    
  4. Exception Parameter in Catch Blocks:

    static void parseInteger(String input) {
        try {
            int num = Integer.parseInt(input);
            System.out.println(num + " is a valid number");
        } catch (NumberFormatException _) {
            System.out.println("Invalid number format");
        }
    }
    
  5. Lambda Parameter:

    record Circle(double radius) {}
    record Drawing(String id, Circle shape) {}
    static Map<String, String> getDrawingIDs(List<Drawing> drawings) {
        return drawings.stream().collect(Collectors.toMap(Drawing::id, _ -> "UNKNOWN"));
    }
    

Unnamed Patterns

Unnamed patterns simplify pattern matching by omitting unused variables in record patterns.

Example: Eliminating Unused Pattern Variables

Without Unnamed Patterns

record Coordinates(double latitude, double longitude) {}
enum Status { ACTIVE, INACTIVE, PENDING }
record Location(Coordinates coord, Status status) {}

double calculateDistance(Object loc1, Object loc2) {
    if (loc1 instanceof Location(Coordinates c1, Status s1) &&
        loc2 instanceof Location(Coordinates c2, Status s2)) {
        return Math.sqrt(Math.pow(c2.latitude - c1.latitude, 2) + Math.pow(c2.longitude - c1.longitude, 2));
    }
    return -1;
}
Enter fullscreen mode Exit fullscreen mode

With Unnamed Patterns

double calculateDistance(Object loc1, Object loc2) {
    if (loc1 instanceof Location(Coordinates c1, _) &&
        loc2 instanceof Location(Coordinates c2, _)) {
        return Math.sqrt(Math.pow(c2.latitude - c1.latitude, 2) + Math.pow(c2.longitude - c1.longitude, 2));
    }
    return -1;
}
Enter fullscreen mode Exit fullscreen mode

Here, _ replaces the unused Status components, making the code cleaner.

Restrictions on Unnamed Patterns

  • You cannot use _ as a top-level pattern:

    // Compiler error
    if (loc1 instanceof _) {
        // ...
    }
    
  • You cannot use _ as a reference:

    // Compiler error
    if (loc1 instanceof Location(Coordinates c1, Status _)) {
        System.out.println("Status: " + _); // Invalid
    }
    

Using Unnamed Patterns in Switch Statements

Unnamed patterns are useful in switch expressions and statements:

sealed interface User permits Admin, Guest, Member { }
record Admin(String name, int accessLevel) implements User { }
record Guest(String name) implements User { }
record Member(String name) implements User { }

void displayAccess(User user) {
    switch (user) {
        case Admin a   -> System.out.println("Access Level: " + a.accessLevel());
        case Guest _, Member _ -> System.out.println("Limited Access");
    }
}
Enter fullscreen mode Exit fullscreen mode

Using multiple unnamed patterns in case labels helps group similar cases together, improving readability.

Conclusion

Unnamed variables and patterns in Java 23 enhance code clarity by allowing developers to omit unnecessary variables and patterns. They improve readability, reduce redundancy, and streamline pattern matching. By adopting these new features, developers can write cleaner and more maintainable Java code.

Top comments (0)