We're trying to make long chains of if statements clearer (and potentially faster) by converting them into switches.
if statementsif ... else if ... else if ... statements has K total branches, at runtime one needs to check O(K) conditions on average (assuming equal likelihood of each branch)if (...). Besides redundancy, this introduces a potential bug vector: an if in the chain could unintentionally have a slightly different condition than others, an ordering bug (see below), etc.switches:1, 2, ...), enum values, null, and pattern matching, including mixtures of theseenum 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.
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.
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.)