This document proposes changes to the Java Language Specification to support extensions to the switch statement so that it can be used as either a statement or an expression, and improve how it handles nulls and values of other types. See JEP 325 for an overview.

To assist reading, this document contains complete replacements for sections 14.1, 14.11, 14.15, 14.16, 14.17, 15.1 along with an entirely new section 15.29. In the replacement sections, new text is highlighted as this and deleted text is highlighted as this.

14.1. Normal and Abrupt Completion of Statements

Every statement has a normal mode of execution in which certain computational steps are carried out. The following sections describe the normal mode of execution for each kind of statement.

If all the steps are carried out as described, with no indication of abrupt completion, the statement is said to complete normally. However, certain events may prevent a statement from completing normally:

If such an event occurs, then execution of one or more statements may be terminated before all steps of their normal mode of execution have completed; such statements are said to complete abruptly.

An abrupt completion always has an associated reason, which is one of the following:

The terms “complete normally” and “complete abruptly” also apply to the evaluation of expressions (15.6). The only reason an expression can complete abruptly is that an exception is thrown, because of either a throw with a given value (14.18) or a run-time exception or error ([11 (Exceptions)], 15.6).

If a statement evaluates an expression, abrupt completion of the expression always causes the immediate abrupt completion of the statement, with the same reason. All succeeding steps in the normal mode of execution are not performed.

Unless otherwise specified in this chapter, abrupt completion of a substatement causes the immediate abrupt completion of the statement itself, with the same reason, and all succeeding steps in the normal mode of execution of the statement are not performed.

Unless otherwise specified, a statement completes normally if all expressions it evaluates and all substatements it executes complete normally.

14.11. The switch Statement

The switch statement transfers control to one of several statements depending on the value of an expression. This expression is known as the selector expression.

SwitchStatement:

switch ( Expression ) SwitchBlock SwitchStatementBlock

SwitchBlock:

{ {SwitchBlockStatementGroup} {SwitchLabel} }

SwitchBlockStatementGroup:

SwitchLabels BlockStatements

SwitchLabels:

SwitchLabel {SwitchLabel}

SwitchLabel:

case ConstantExpression :
case EnumConstantName :
default :

SwitchStatementBlock:

{ { SwitchBlockStatementGroup } { PatternLabel } }

SwitchBlockStatementGroup:

PatternLabels BlockStatements

PatternLabels:

PatternLabel { PatternLabel }

PatternLabel:

case Pattern { , Pattern }:
default :

Pattern:

ConstantExpression
EnumConstantName
null

EnumConstantName:

Identifier

The type of the selector expression must be a primitive type, a boxed primitive type, String, or an enum type [8.9], or a compile-time error occurs.

The body of a switch statement is known as a switch statement block. Any statement immediately contained by the switch statement block may be associated with one or more pattern labels, which is either a case pattern label or a default pattern label. Every case pattern label has at least one pattern, which is either a constant expression, the name of an enum constant, or the null literal. Patterns labels and patterns are said to be associated with the switch statement.

Given a switch statement, all of the following must be true or a compile-time error occurs:

–Start-of-discussion

The prohibition against using null as a case constant prevents code being written that can never be executed. If the switch statement’s Expression is of a reference type, that is, String or a boxed primitive type or an enum type, then an exception will be thrown will occur if the Expression evaluates to null at run time. In the judgment of the designers of the Java programming language, this is a better outcome than silently skipping the entire switch statement or choosing to execute the statements (if any) after the default label (if any).

The null literal is considered a valid pattern associated with a switch statement. This provides the flexibility of defining specific logic for this case. However, if no null pattern is associated with the switch statement, and the selector expression evaluates to null at run time, then an exception will be thrown. This behaviour ensures compatibility with previous versions of the switch statement.

A Java compiler is encouraged (but not required) to provide a warning if a switch on an enum-valued expression lacks a default label and lacks case labels for one or more of the enum’s constants. Such a switch will silently do nothing if the expression evaluates to one of the missing constants.

In C and C++ the body of a switch statement can be a statement and statements with case heads do not have to be immediately contained by that statement. Consider the simple loop:

for (i = 0; i < n; ++i) foo();

where n is known to be positive. A trick known as Duff’s device can be used in C or C++ to unroll the loop, but this is not valid code in the Java programming language:

int q = (n+7)/8;
switch (n%8) {
    case 0: do { foo();    // Great C hack, Tom,
    case 7:      foo();    // but it's not valid here.
    case 6:      foo();
    case 5:      foo();
    case 4:      foo();
    case 3:      foo();
    case 2:      foo();
    case 1:      foo();
            } while (--q > 0);
}

Fortunately, this trick does not seem to be widely known or used. Moreover, it is less needed nowadays; this sort of code transformation is properly in the province of state-of-the-art optimizing compilers.

–End-of-discussion

When the switch statement is executed, first the selector expression is evaluated; exactly one of three outcomes are possible.

1. If evaluation of the selector expression completes abruptly for some reason, the switch statement completes abruptly for the same reason.

2. If the selector expression evaluates to null, and there is no null pattern associated with the switch statement, then a NullPointerException is thrown and the entire switch statement completes abruptly for that reason.

3. Otherwise, execution continues by matching the value of the selector expression with each pattern (in cases where the selector expression is of a boxed primitive type and the pattern is not a null pattern, the value of the selector expression is first subject to an unboxing conversion 5.1.8), and there is a choice:

If in matching the selector expression with a pattern, an unboxing conversion is applied and completes abruptly for some reason, the switch statement completes abruptly for the same reason.

If any statement immediately contained by the SwitchStatementBlock body of the switch statement completes abruptly, it is handled as follows:

Note that it is not possible for the execution of the Statement to complete abruptly because of a break with a value.

–Start-of-discussion

The case of abrupt completion because of a break with a label is handled by the general rule for labeled statements 14.7.

It is important to note that a default pattern label in a switch statement does not match a selector expression that evaluates to the null at run time. If there is no null pattern then the switch statement throws an exception, otherwise it matches the null pattern. Examples of nulls and patterns are given in this example.

String s;
switch (s) {
    case null: System.out.println("That's a null!");
}
switch (s) {
    case "Hello": {
        System.out.println("Same to you!");
        break;
    }                      // No null pattern, so will throw an exception
}
switch (s) {
                           // Even default does not match
                           // Will throw an exception
    default: 
         System.out.println("It's a string");    
}

A pattern label can contain multiple patterns, and is said to match if any one of these patterns matches. The pattern label can then be seen to be a disjunction of its constituent patterns.

switch (day) {
    case SATURDAY, SUNDAY: 
        // matches if it is a Saturday OR a Sunday
        System.out.println("It's the weekend!");
}

Example 14.11-1. Fall-Through in the switch Statement

As in C and C++, execution of statements in a switch block “falls through labels.”

For example, the program:

class TooMany {
    static void howMany(int k) {
        switch (k) {
            case 1: System.out.print("one ");
            case 2: System.out.print("too ");
            case 3: System.out.println("many");
        }
    }
    public static void main(String args) {
        howMany(3);
        howMany(2);
        howMany(1);
    }
}

contains a switch block in which the code for each case falls through into the code for the next case. As a result, the program prints:

many
too many
one too many

If code is not to fall through case to case in this manner, then break statements should be used, as in this example:

class TwoMany {
    static void howMany(int k) {
        switch (k) {
            case 1: System.out.println("one");
                    break;  // exit the switch
            case 2: System.out.println("two");
                    break;  // exit the switch
            case 3: System.out.println("many");
                    break;  // not needed, but good style
        }
    }
    public static void main(String args) {
        howMany(1);
        howMany(2);
        howMany(3);
    }
}

This program prints:

one
two
many

–End-of-discussion

14.15. The break Statement

A break statement either transfers control out of an enclosing statement or returns a value to an immediately enclosing switch expression.

BreakStatement:

break ;
break Identifier ;
break Expression ;

A break statement with no label or value attempts to transfer control to the innermost enclosing switch, while, do, or for statement of the immediately enclosing method or initializer; this statement, which is called the break target, then immediately completes normally.

To be precise, a break statement with no label or value always completes abruptly, the reason being a break with no label or value.

A break statement with no label or value is not permitted to transfer control through a switch expression. If the break target contains a switch expression which itself encloses the break statement, a compile-time error occurs.

If no switch, while, do, or for statement in the immediately enclosing method, constructor, or initializer contains the break statement with no label or value, a compile-time error occurs.

A break statement with label Identifier attempts to transfer control to the enclosing labeled statement 14.7 that has the same Identifier as its label; this statement, which is called the break target, then immediately completes normally. In this case, the break target need not be a switch, while, do, or for statement.

To be precise, a break statement with label Identifier always completes abruptly, the reason being a break with label Identifier.

A break statement must refer to a label within the immediately enclosing method, constructor, initializer, or lambda body, or switch expression block. There are no non-local jumps. If no labeled statement with Identifier as its label in the immediately enclosing method, constructor, initializer, or lambda body, or switch expression block contains the break statement, a compile-time error occurs.

A break statement with an Expression attempts to cause the evaluation of the immediately enclosing switch expression 15.29 to complete normally with the value of the Expression; this switch expression is called the break target. Should the evaluation of the Expression complete abruptly for some reason, the break statement completes abruptly for the same reason, and the immediately enclosing switch expression completes abruptly for the same reason.

To be precise, a break statement with an Expression always completes abruptly, the reason being a break with a given value that is equal to the value of the Expression.

If there is no immediately enclosing switch expression for a break statement with an Expression, a compile-time error occurs.

If a break statement with an Expression is contained in a switch, while, do, or for statement which itself is enclosed in the break target, or is enclosed by a lambda body which itself is enclosed in the break target, then a compile-time error occurs.

If a break statement with an Expression is contained in a labeled statement, where the Expression is a simple name (15.14.1) that consists of the same identifier as the label, then a compile-time error occurs.

It can be seen, then, that all forms of break statement always complete abruptly.

–Start-of-discussion

The preceding descriptions say “attempts to transfer control” rather than just “transfers control” because if there are any try statements 14.20 within the break target whose try blocks or catch clauses contain the break statement, then any finally clauses of those try statements are executed, in order, innermost to outermost, before control is transferred to the break target. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a break statement.

Example 14.15-1. The break Statement

In the following example, a mathematical graph is represented by an array of arrays. A graph consists of a set of nodes and a set of edges; each edge is an arrow that points from some node to some other node, or from a node to itself. In this example it is assumed that there are no redundant edges; that is, for any two nodes P and Q, where Q may be the same as P, there is at most one edge from P to Q.

Nodes are represented by integers, and there is an edge from node i to node edges[i][j] for every i and j for which the array reference edges[i][j] does not throw an ArrayIndexOutOfBoundsException.

The task of the method loseEdges, given integers i and j, is to construct a new graph by copying a given graph but omitting the edge from node i to node j, if any, and the edge from node j to node i, if any:

class Graph {
    int edges;
    public Graph(int edges) { this.edges = edges; }

    public Graph loseEdges(int i, int j) {
        int n = edges.length;
        int newedges = new int[n];
        for (int k = 0; k < n; ++k) {
edgelist:
{
            int z;
search:
{
            if (k == i) {
                for (z = 0; z < edges[k].length; ++z) {
                    if (edges[k][z] == j) break search;
                }
            } else if (k == j) {
                for (z = 0; z < edges[k].length; ++z) {
                    if (edges[k][z] == i) break search;
                }
            }

            // No edge to be deleted; share this list.
            newedges[k] = edges[k];
            break edgelist;
} //search

            // Copy the list, omitting the edge at position z.
            int m = edges[k].length - 1;
            int ne = new int[m];
            System.arraycopy(edges[k], 0, ne, 0, z);
            System.arraycopy(edges[k], z+1, ne, z, m-z);
            newedges[k] = ne;
} //edgelist
        }
        return new Graph(newedges);
    }
}

Note the use of two statement labels, edgelist and search, and the use of break statements. This allows the code that copies a list, omitting one edge, to be shared between two separate tests, the test for an edge from node i to node j, and the test for an edge from node j to node i.

14.16. The continue Statement

A continue statement may occur only in a while, do, or for statement; statements of these three kinds are called iteration statements. Control passes to the loop-continuation point of an iteration statement.

ContinueStatement:

continue [Identifier] ;

A continue statement with no label attempts to transfer control to the innermost enclosing while, do, or for statement of the immediately enclosing method, constructor, or initializer; this statement, which is called the continue target, then immediately ends the current iteration and begins a new one.

To be precise, such a continue statement always completes abruptly, the reason being a continue with no label.

If no while, do, or for statement of the immediately enclosing method, constructor, or initializer contains the continue statement, a compile-time error occurs.

A continue statement with label Identifier attempts to transfer control to the enclosing labeled statement (14.7) that has the same Identifier as its label; that statement, which is called the continue target, then immediately ends the current iteration and begins a new one.

To be precise, a continue statement with label Identifier always completes abruptly, the reason being a continue with label Identifier.

The continue target must be a while, do, or for statement, or a compile-time error occurs.

A continue statement must refer to a label within the immediately enclosing method, constructor, initializer, or lambda body, or switch expression block. There are no non-local jumps. If no labeled statement with Identifier as its label in the immediately enclosing method, constructor, initializer, or lambda body, or switch expression block contains the continue statement, a compile-time error occurs.

A continue statement is not permitted to transfer control through a switch expression. If the continue target contains a switch expression which itself encloses the continue statement, a compile-time error occurs.

It can be seen, then, that a continue statement always completes abruptly.

See the descriptions of the while statement (14.12), do statement (14.13), and for statement (14.14) for a discussion of the handling of abrupt termination because of continue.

The preceding descriptions say “attempts to transfer control” rather than just “transfers control” because if there are any try statements (14.20) within the continue target whose try blocks or catch clauses contain the continue statement, then any finally clauses of those try statements are executed, in order, innermost to outermost, before control is transferred to the continue target. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a continue statement.

Example 14.16-1. The continue Statement

In the Graph class in 14.15, one of the break statements is used to finish execution of the entire body of the outermost for loop. This break can be replaced by a continue if the for loop itself is labeled:

class Graph {
    int edges[][];
    public Graph(int[][] edges) { this.edges = edges; }

    public Graph loseEdges(int i, int j) {
        int n = edges.length;
        int[][] newedges = new int[n][];
edgelists:
        for (int k = 0; k < n; ++k) {
            int z;
search:
{
            if (k == i) {
                for (z = 0; z < edges[k].length; ++z) {
                    if (edges[k][z] == j) break search;
                }
            } else if (k == j) {
                for (z = 0; z < edges[k].length; ++z) {
                    if (edges[k][z] == i) break search;
                }
            }

            // No edge to be deleted; share this list.
            newedges[k] = edges[k];
            continue edgelists;
} //search

            // Copy the list, omitting the edge at position z.
            int m = edges[k].length - 1;
            int ne[] = new int[m];
            System.arraycopy(edges[k], 0, ne, 0, z);
            System.arraycopy(edges[k], z+1, ne, z, m-z);
            newedges[k] = ne;
        } //edgelists
        return new Graph(newedges);
    }
}

Which to use, if either, is largely a matter of programming style.

14.17. The return Statement

A return statement returns control to the invoker of a method (8.4, 15.12) or constructor ([8.8], [15.9]).

ReturnStatement:

return [Expression] ;

A return statement is contained in the innermost constructor, method, initializer, or lambda expression whose body encloses the return statement.

A return statement is not permitted to return control through a switch expression. If a return statement is contained in a switch expression that is itself contained in the innermost constructor, method, initializer, or lambda expression whose body encloses the return statement then a compile-time error occurs.

It is a compile-time error if a return statement is contained in an instance initializer or a static initializer ([8.6], [8.7]).

A return statement with no Expression must be contained in one of the following, or a compile-time error occurs:

A return statement with no Expression attempts to transfer control to the invoker of the method, constructor, or lambda body that contains it. To be precise, a return statement with no Expression always completes abruptly, the reason being a return with no value.

A return statement with an Expression must be contained in one of the following, or a compile-time error occurs:

The Expression must denote a variable or a value, or a compile-time error occurs.

When a return statement with an Expression appears in a method declaration, the Expression must be assignable (5.2) to the declared return type of the method, or a compile-time error occurs.

A return statement with an Expression attempts to transfer control to the invoker of the method or lambda body that contains it; the value of the Expression becomes the value of the method invocation. More precisely, execution of such a return statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the return statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the return statement completes abruptly, the reason being a return with value V.

If the expression is of type float and is not FP-strict (15.4), then the value may be an element of either the float value set or the float-extended-exponent value set (4.2.3). If the expression is of type double and is not FP-strict, then the value may be an element of either the double value set or the double-extended-exponent value set.

It can be seen, then, that a return statement always completes abruptly.

The preceding descriptions say “attempts to transfer control” rather than just “transfers control” because if there are any try statements (14.20) within the method or constructor whose try blocks or catch clauses contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.

15.1. Evaluation, Denotation, and Result

When an expression in a program is evaluated (executed), the result denotes one of three things:

If an expression denotes a variable, and a value is required for use in further evaluation, then the value of that variable is used. In this context, if the expression denotes a variable or a value, we may speak simply of the value of the expression.

Value set conversion (5.1.13) is applied to the result of every expression that produces a value, including when the value of a variable of type float or double is used.

An expression denotes nothing if and only if it is a method invocation (15.12) that invokes a method that does not return a value, that is, a method declared void (8.4). Such an expression can be used only as an expression statement (14.8) or as the single expression of a lambda body (15.27.2), because every other context in which an expression can appear requires the expression to denote something. An expression statement or lambda body that is a method invocation may also invoke a method that produces a result; in this case the value returned by the method is quietly discarded.

Evaluation of an expression can produce side effects, because expressions may contain embedded assignments, increment operators, decrement operators, and method invocations. In addition, lambda expressions and switch expressions have bodies that may contain arbitrary statements.

An expression occurs in either:

15.29. switch Expressions

A switch expression is an expression analogue of the switch statement (14.11). It consists of a selector expression and an switch expression block containing one or more groups. A switch expression matches the value of the selector expression against the pattern labels associated with the switch block to determine which of the groups to execute to return a value. In contrast to a switch statement, every group must return a value, or fall through to one that does. In addition, for all possible values of the selector expression the switch expression either completes normally with a value or completes abruptly.

SwitchExpression:

switch ( Expression ) SwitchExpressionBlock

SwitchExpressionBlock:

{ SwitchExpressionGroup { SwitchExpressionGroup } }

SwitchExpressionGroup:

SwitchBlockStatementGroup
SwitchBlockClause

SwitchBlockClause:

case Pattern { , Pattern } -> Expression ;
case Pattern { , Pattern } -> ThrowStatement
default -> Expression ;
default -> ThrowStatement

A switch expression is always a poly expression ([15.2]). TO DO: Need to decide this

–Start-of-Discussion

A switch expression can be particularly useful when combining computation with assignment, as in the following example.

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};

A switch expression can be freely used as a subexpression in other expressions and statements, as in the following examples.

if (switch (getCurrentDay()){ 
    case MONDAY, WEDNESDAY -> true; 
    default                -> false 
}) {
    // Code to deal with Mondays and Wednesdays
}
PrintOutMessage(switch (getCurrentDay()){ 
    case SATURDAY, SUNDAY -> 1; 
    default               -> 0; 
});

It is expected that most uses of a switch expression will use the compact clause form. However, there are circumstances where a statement form is needed. In this case, the switch expression supports switch block statement groups (14.11). However these statement groups must either return a value using a break statement with an Expression (14.15) or fall through to a switch expression group that eventually returns a value.

The following program uses all switch block statement groups in a switch expression.

int result = switch (s) {
    case SATURDAY:
        break 1;
    case SUNDAY:
        break 2;
    default:
        System.out.println("Need to wait...");
        break 0;
}

A switch expression supports the use of both group forms in the same block. The declaration above can be written equivalently as follows.

int result = switch (s) {
    case SATURDAY:
        break 1;
    case SUNDAY -> 2;
    default:
        System.out.println("Need to wait...");
        break 0;
}

The following example shows how a switch block statement group can fall through in a switch expression.

boolean isStartOfTheWeek = switch (day) {
    case MONDAY: System.out.println("It's a Monday");
    case TUESDAY, WEDNESDAY: break true;
    default: break false;
}

For convenience the right hand side of a switch block clause can be a throw statement, as in the following example.

int result = switch (startingDay) {
    case MONDAY -> 1;
    case SATURDAY, SUNDAY -> throw new IncorrectStartingDayException();
    default:
        System.out.println("Strange, but allowed...");
        break 0;
}

–End-of-Discussion

The rules for the selector expression in the switch expression are as set out in (14.11).

The body of a switch expression, called the switch expression block, consists of one or more switch expression groups.

The groups in an expression switch are either switch block statement groups or switch block clauses.

A switch block statement group is defined in (14.11) and consists of one or more pattern labels followed by one or more block statements. A pattern label is either a case pattern label or a default pattern label. Every case pattern label has at least one pattern, which is either a constant expression or the name of an enum constant. Patterns and pattern labels are said to be associated with the switch expression.

A switch block clause consists of either a case pattern label and an expression, or a case pattern label and a throw statement, or a default pattern label and an expression, or a default pattern label and a throw statement.

The meaning of a switch block clause of the form

case Pattern -> Expression;

is given by the following translation to a switch block statement group:

case Pattern: break Expression;

The meaning of a switch block clause of the form

case Pattern -> throw Expression;

is given by the following translation to a switch block statement group:

case Pattern: throw Expression;

The meaning of a switch block clause of the form

default -> Expression;

is given by the following translation to a switch block statement group:

default: break Expression;

The meaning of a switch block clause of the form

default -> throw Expression;

is given by the following translation to a switch block statement group:

default: throw Expression;

Given a switch expression, all of the following must be true or a compile-time error occurs:

–Start-of-Discussion

The final case rules out a switch expression that contain both a default expression clause and a default statement group.

int temp = switch (x) {
    default -> 1;
    default: break 2;     // illegal, more than one default
}

–End-of-discussion

Totality

Evaluating a switch expression must result in a value or complete abruptly for all possible values of the selector expression. To ensure this it is required that the pattern labels exhaustively cover all the possible values of the selector expression.

A switch expression is total if at least one of the following is true:

It is a compile-time error if a switch expression is not total.

–Start-of-discussion Some examples of total and non-total switch expressions are as follows.

int temp = switch (day) {
    case SATURDAY, SUNDAY -> 42; // illegal, non-total
}
int temp2 = switch (day) {
    case MONDAY -> 42;
    default     -> 0;      // Legal, total
}
int temp3 = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;  // Legal, note no default needed!
}
int temp4 = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;  
    default                     -> 10; // Legal
}

–End-of-discussion

Non-returning

Evaluating a switch expression, as for all expressions, must complete normally with a value or complete abruptly with the reason that an exception is thrown. A switch expression completes normally by executing a break statement with an Expression in its body. It must not be possible to simply fall through the body of a switch expression, in which case there would be no resulting value.

A switch expression is non-returning if its switch block can complete normally. It is a compile-time error if a switch expression is non-returning. Ensuring a switch expression is not non-returning is sufficient to ensure that it completes normally with a value or completes abruptly.

–Start-of-discussion

This non-returning requirement on switch expressions is worthy of further comment. In the absence of nested statements, an occurrence of a break statement with an Expression in a switch expression means that the switch expression will complete normally with the the value of the Expression. Occurrences of return and continue statements are forbidden, as are break statements with a label and break statements with no label or value. Thus a switch expression block that can not complete normally, can only do so by occurrences of a break statement with an Expression. This ensures that a switch expression must either result in a value, or complete abruptly.

loop:
for (...) {
    sum += switch (x) {
        case 1 -> 2;
        case 2 -> 4;
        default:
            break loop;  // illegal break statement with a label
    }
}

No statement immediately enclosed in a switch expression body may contain a return statement that returns out of the enclosing method. Similarly, they cannot contain a break or continue statement if doing so would break through the switch expression.

loop:
for (...) {
    int x = switch (y) {
        case 1:
            switch (z) {
                case 1: break loop;  // illegal break with a label
                case 2: continue;    // illegal continue
                case 3: return null; // illegal return
            }
         case 2:
             if (y < z)
                 return null;        // illegal return
}

–End-of-discussion

When the switch expression is executed, first the selector expression is evaluated; exactly one of three outcomes are possible.

  1. If evaluation of the selector expression completes abruptly for some reason, the switch expression completes abruptly for the same reason.

  2. If the selector expression evaluates to null, and there is no null pattern associated with the switch expression, then a NullPointerException is thrown and the entire switch expression completes abruptly for that reason.

  3. Otherwise, execution continues by matching the value of the selector expression with each pattern (in cases where the selector expression is of a boxed primitive type and the pattern is not a null pattern, the value of the selector expression is first subject to an unboxing conversion (5.1.8)), and there is a choice:

    • If one of the patterns is null and the selector expression evaluates to null, then we say that the null pattern matches. All statements after the pattern label containing the null pattern in the switch block, if any, are executed in sequence. Note that because of the non-returning requirement, it is not possible for all these statements to complete normally.

    • If one of the patterns is a constant expression or enum constant that is equal to the value of the selector expression, then we say that the pattern matches. All statements after the pattern label containing the matching pattern in the switch block, if any, are executed in sequence. Note that because of the non-returning requirement, it is not possible for all these statements to complete normally.

    • If no pattern matches but there is a default pattern label, then all statements after the default pattern label in the switch block are executed in sequence. Note that because of the non-returning requirement, it is not possible for all these statements to complete normally, nor for there to be no statements after the default pattern label.

    • If no pattern matches and there is no default pattern label, then a ?? is thrown and the entire switch expression completes abruptly for that reason.

If in matching the selector expression with a pattern, an unboxing conversion is applied and completes abruptly for some reason, the switch expression completes abruptly for the same reason.

If any statement immediately contained by the SwitchExpressionBlock completes abruptly, it is handled as follows: