IfChainToSwitch
This if-chain may be converted into a switch

Severity
WARNING

The problem

We’re trying to make long chains of if statements clearer (and potentially faster) by converting them into switches.

Long chains of if statements

switches:

Examples

1. Enum conversion

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

private void foo(Suit suit) {
  if (suit == Suit.SPADE) {
    System.out.println("spade");
  } else if (suit == Suit.DIAMOND) {
    System.out.println("diamond");
  } else if (suit == Suit.HEART) {
    System.out.println("heart);
  } else if (suit == Suit.CLUB) {
    System.out.println("club");
  }
}

Which can be converted into:

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

private void foo(Suit suit) {
  switch (suit) {
    case Suit.SPADE -> System.out.println("spade");
    case Suit.DIAMOND -> System.out.println("diamond");
    case Suit.HEART -> System.out.println("heart");
    case Suit.CLUB -> System.out.println("club");
  }
}

Note that with the new switch style (->), one gets exhaustiveness checking “for free”. That is, if a new Suit value were to be added to the enum, then the switch would raise a compile-time error, whereas the original chain of if statements would need to be manually detected and edited.

2. Patterns

This conversion works for instanceofs too:

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

private void describeObject(Object obj) {

  if (obj instanceof String) {
    System.out.println("It's a string!");
  } else if (obj instanceof Number n) {
    System.out.println("It's a number!");
  } else if (obj instanceof Object) {
    System.out.println("It's an object!");
  }
}

This can be converted as follows (if the instanceof does not originally have a pattern variable, then unused will be inserted):

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

private void describeObject(Object obj) {

  switch(obj) {
    case String unused -> System.out.println("It's a string!");
    case Number n -> System.out.println("It's a number!");
    case Object unused -> System.out.println("It's an object!");
  }
}

In later Java versions, an unnamed variable (_) can be used in place of unused.

3. Ordering Bugs

With if chains, it’s possible to write code such as:

private void describeObject(Object obj) {

  if (obj instanceof Object) {
    System.out.println("It's an object!");
  } else if (obj instanceof Number n) {
    System.out.println("It's a number!");
  } else if (obj instanceof String) {
    System.out.println("It's a string!");
  }
}

When calling describeObject("hello"), one might expect to have It's a string! printed, but this is not what happens. Because the Object check happens first in code, it matches, resulting in It's an object!. This behavior is most likely a bug, and can sometimes be hard to spot. (This check can be suppressed if the behavior is intentional.)

Suppression

Suppress false positives by adding the suppression annotation @SuppressWarnings("IfChainToSwitch") to the enclosing element.