| Including a default case is redundant when switching on an enum type if the |
| switch handles all possible values of the enum, and execution cannot fall |
| through from a `case` into the `default`. |
| |
| Note: This check does not apply to pseudo-enums such as Android `@IntDef`s, |
| which are integers that are treated specially by other tools. |
| |
| TIP: Removing the unnecessary default allows Error Prone to enforce that the |
| switch continues to handle all cases, even if new values are added to the enum, |
| see: [MissingCasesInEnumSwitch](MissingCasesInEnumSwitch.md). After the |
| unnecessary default is removed, Error Prone will report an error if new enum |
| constants are added in the future, to remind you to either handle the cases |
| explicitly or restore the default case. |
| |
| ## When the default can be removed |
| |
| This check does not report cases where execution can continue after the switch |
| statement from any non-default statement groups, and removing the `default` |
| would prevent the code from compiling. For example, consider: |
| |
| ```java |
| enum TrafficLightColour { RED, GREEN, YELLOW } |
| |
| void approachIntersection(TrafficLightColour state) { |
| boolean stop; |
| switch (state) { |
| case GREEN: |
| stop = false; |
| break; |
| case YELLOW: |
| case RED: |
| stop = true; |
| break; |
| } |
| if (stop) { |
| ... |
| } |
| } |
| ``` |
| |
| The definition of control flow in [JLS §14.21] does not consider whether enum |
| switches handle all cases, so in the example above javac will complain that |
| `stop` is not definitely assigned. This is because adding constants to an enum |
| is a binary compatible change (see [JLS §13.4.26]), so the spec allows for the |
| possibility that `TrafficLightColour` is defined in another library, and after |
| compiling our code we update to a new version of the library (without |
| recompiling) that adds another colour of traffic light (say, `PURPLE`) that the |
| switch doesn't handle. |
| |
| This check should be used together with `MissingCasesInEnumSwitch` in |
| environments where that kind of binary incompatibility is very unlikely. For |
| example, if your build system accurately tracks changes to dependencies and you |
| are deploying an application (instead of a library), the risk of skew between |
| compile-time and runtime is minimal. On the other hand, if you are a library |
| author and your code switches on an enum in a different library, you want to |
| include 'defensive' default cases to handle the situation where a user deploys |
| your code together with an incompatible version of the other library. |
| |
| [JLS §14.21]: https://docs.oracle.com/javase/specs/jls/se10/html/jls-14.html#jls-14.21 |
| [JLS §13.4.26]: https://docs.oracle.com/javase/specs/jls/se10/html/jls-13.html#jls-13.4.26 |
| |
| ## Examples |
| |
| The following examples show situations where it is usually safe to remove the |
| default from an exhaustive enum switch. |
| |
| ### All cases return or throw |
| |
| Before: |
| |
| ```java |
| enum State { ON, OFF } |
| |
| boolean isOn(State state) { |
| switch (state) { |
| case ON: |
| return true; |
| case OFF: |
| return false; |
| default: |
| throw new AssertionError(state); |
| } |
| } |
| ``` |
| |
| After: |
| |
| ```java |
| enum State { ON, OFF } |
| |
| boolean isOn(State state) { |
| switch (state) { |
| case ON: |
| return true; |
| case OFF: |
| return false; |
| } |
| throw new AssertionError(state); |
| } |
| ``` |
| |
| ### The default case is empty |
| |
| Before: |
| |
| ```java |
| enum State { ON, OFF } |
| |
| boolean isOn(State state) { |
| switch (state) { |
| case ON: |
| return true; |
| case OFF: |
| break; |
| default: |
| break; |
| } |
| return false; |
| } |
| ``` |
| |
| After: |
| |
| ```java |
| enum State { ON, OFF } |
| |
| boolean isOn(State state) { |
| switch (state) { |
| case ON: |
| return true; |
| case OFF: |
| break; |
| } |
| return false; |
| } |
| ``` |
| |
| ## Cases with UNRECOGNIZED |
| |
| proto3 enums implicitly add an UNRECOGNIZED value to all enums. If a switch |
| statement handles all values of a proto-generated enum except for UNRECOGNIZED, |
| and has a default cause, we assume this is an attempt to exhaustively cover all |
| cases. But in the future, if a new enum value is added, that case will be |
| silently caught up in the default case. To avoid this, remove the default case |
| and handle UNRECOGNIZED explicitly. This way, `MissingCasesInEnumSwitch` will |
| catch unexpected enum types at compile-time instead of runtime. |
| |
| If the switch statement cannot [complete normally], the default should be |
| deleted and its statements moved after the switch statement. The UNRECOGNIZED |
| case should be added with a break. |
| |
| If it can complete normally, the default should be merged with an added |
| UNRECOGNIZED case. |
| |
| [complete normally]: https://docs.oracle.com/javase/specs/jls/se10/html/jls-14.html#jls-14.1 |
| |
| ## Library skew |
| |
| A default branch that has a comment containing "skew" will not be classified as |
| unnecessary. See: [MissingCasesInEnumSwitch](MissingCasesInEnumSwitch.md). |