In a colon-style switch, case labels do not introduce separate lexical scopes. A local variable declared directly in one case group remains in scope in later case groups.

Why is this an issue?

Case groups look like separate branches, so readers commonly expect variables declared in one group to belong only to that group. When a later group accesses such a variable, its actual scope no longer matches the visual structure of the code. Understanding the variable then requires tracing its declaration and every later case group, which makes the switch harder to read and maintain.

Java’s definite-assignment rules prevent reading a local variable before it has been assigned. This rule does not identify uninitialized reads. It reports variables that are assigned or otherwise accessed across distinct case groups because sharing them obscures their scope.

Consecutive case labels form one case group and do not trigger an issue by themselves. Declarations inside their own block are also excluded because the block limits the variable’s scope.

How to fix it

Give each case group its own variable. For colon-style switches, enclose each group’s statements in a block. Alternatively, use arrow-style rules, which naturally isolate the code for each branch.

Code examples

Noncompliant code example

void logState(State state) {
  switch (state) {
    case NEW:
    case QUEUED:
      String message = "Waiting"; // Noncompliant
      log(message);
      break;
    case RETRY:
      message = "Retrying"; // Accessed from this later case group.
      log(message);
      break;
    case FAILED:
      message = "Failed"; // Accessed from this later case group.
      log(message);
      break;
  }
}

Compliant solution

void logState(State state) {
  switch (state) {
    case NEW:
    case QUEUED: {
      String message = "Waiting";
      log(message);
      break;
    }
    case RETRY: {
      String message = "Retrying";
      log(message);
      break;
    }
    case FAILED: {
      String message = "Failed";
      log(message);
      break;
    }
  }
}

Noncompliant code example

int priority(State state) {
  return switch (state) {
    case NEW:
      int priority = 1; // Noncompliant
      yield priority;
    case RETRY:
      priority = 2; // Accessed from this later case group.
      yield priority;
    default:
      yield 0;
  };
}

Compliant solution

int priority(State state) {
  return switch (state) {
    case NEW -> {
      int priority = 1;
      yield priority;
    }
    case RETRY -> {
      int priority = 2;
      yield priority;
    }
    default -> 0;
  };
}

Resources

Documentation