All Downloads are FREE. Search and download functionalities are using the official Maven repository.

errorprone.bugpattern.StatementSwitchToExpressionSwitch.md Maven / Gradle / Ivy

The newest version!
We're trying to make `switch` statements simpler to understand at a glance.
Misunderstanding the control flow of a `switch` block is a common source of
bugs.

### Statement `switch` statements:

*   Have a colon between the `case` and the case's code. For example, `case
    HEARTS:`
*   Because of the potential for fall-through, it takes time and cognitive load
    to understand the control flow for each `case`
*   When a `switch` block is large, just skimming each `case` can be toilsome
*   Fall-though can also be conditional (see example below). In this scenario,
    one would need to reason about all possible flows for each `case`. When
    conditionally falling-through multiple `case`s in a row is possible, the
    number of potential control flows can grow rapidly

### Expression `switch` statements

*   Have an arrow between the `case` and the case's code. For example, `case
    HEARTS ->`
*   With an expression `switch` statement, you know at a glance that no cases
    fall through. No control flow analysis needed
*   Safely and easily reorder `case`s (within a `switch`)
*   It's also possible to group identical cases together (`case A, B, C`) for
    improved readability

### Examples

#### 1. Eliminate fall through

``` {.bad}
enum Suit {HEARTS, CLUBS, SPADES, DIAMONDS};

private void foo(Suit suit) {
  switch(suit) {
    case HEARTS:
      System.out.println("Red hearts");
      break;
    case DIAMONDS:
      System.out.println("Red diamonds");
      break;
    case SPADES:
      // Fall through
    case CLUBS:
      bar();
      System.out.println("Black suit");
    }
}
```

Which can be simplified into the following expression `switch`:

``` {.good}
enum Suit {HEARTS, CLUBS, SPADES, DIAMONDS};

private void foo(Suit suit) {
  switch(suit) {
    case HEARTS -> System.out.println("Red hearts");
    case DIAMONDS -> System.out.println("Red diamonds");
    case SPADES, CLUBS -> {
      bar();
      System.out.println("Black suit");
    }
  }
}
```

#### 2. Return switch

Sometimes `switch` is used with `return`. Below, even though a `case` is
specified for each possible value of the `enum`, note that we nevertheless need
a "should never happen" clause:

``` {.bad}
enum SideOfCoin {OBVERSE, REVERSE};

private String foo(SideOfCoin sideOfCoin) {
  switch(sideOfCoin) {
    case OBVERSE:
      return "Heads";
    case REVERSE:
      return "Tails";
    }
    // This should never happen, but removing this will cause a compile-time error
    throw new RuntimeException("Unknown side of coin");
}
```

Using an expression switch simplifies the code and removes the need for an
explicit "should never happen" clause.

```
enum SideOfCoin {OBVERSE, REVERSE};

private String foo(SideOfCoin sideOfCoin) {
  return switch(sideOfCoin) {
    case OBVERSE -> "Heads";
    case REVERSE -> "Tails";
  };
}
```

If you nevertheless wish to have an explicit "should never happen" clause, this
can be accomplished by placing the logic under a `default` case. For example:

```

enum SideOfCoin {OBVERSE, REVERSE};

private String foo(SideOfCoin sideOfCoin) {
  return switch(sideOfCoin) {
    case OBVERSE -> "Heads";
    case REVERSE -> "Tails";
    default -> {
      // This should never happen
      throw new RuntimeException("Unknown side of coin");
    }
  };
}
```

#### 3. Assignment switch

If every branch of a `switch` is making an assignment to the same variable, it
can be re-written as an assignment switch:

``` {.bad}
enum Suit {HEARTS, CLUBS, SPADES, DIAMONDS};

int score = 0;

private void updateScore(Suit suit) {
  switch(suit) {
    case HEARTS:
      // Fall thru
    case DIAMONDS:
      score += -1;
      break;
    case SPADES:
      score += 2;
      break;
    case CLUBS:
      score += 3;
    }
}
```

This can be simplified as follows:

```
enum Suit {HEARTS, CLUBS, SPADES, DIAMONDS};

int score = 0;

private void updateScore(Suit suit) {
  score += switch(suit) {
    case HEARTS, DIAMONDS -> -1;
    case SPADES -> 2;
    case CLUBS -> 3;
    };
}
```

#### 4. Complex control flows

Here's an example of a complex statement `switch` with conditional fall-through
and complex control flows. How many potential execution paths can you spot?

``` {.bad}
enum Suit {HEARTS, CLUBS, SPADES, DIAMONDS};

private int foo(Suit suit){
  switch(suit) {
    case HEARTS:
      if (bar()) {
        break;
      }
      // Fall through
    case CLUBS:
      if (baz()) {
        return 1;
      } else if (baz2()) {
        throw new AssertionError(...);
      }
      // Fall through
    case SPADES:
      // Fall through
    case DIAMONDS:
      return 0;
  }
  return -1;
}
```




© 2015 - 2025 Weber Informatics LLC | Privacy Policy