The switch Statement with the Arrow (->) Notation – Control Flow

The switch Statement with the Arrow (->) Notation

The form of the switch statement with the arrow notation is shown in Figure 4.4. This form defines switch rules in which each case label is associated with a corresponding action using the arrow (->) notation.

Figure 4.4 Form of the switch Statement with the Arrow Notation

switch (
selector_expression
) {
  // Switch block with switch rules defined using arrow notation:
  case
CC
                  ->
expression_statement
;
  case
CC
1
,
CC
2
, …,
CC
m
  ->
block

  case
CC
4
                 ->
throw_statement

  …
  default                  -> …
}

Compared to the switch statement with the colon notation (Figure 4.2), there are a few things to note.

First, although the case labels (and the default label) are specified similarly, the arrow notation does not allow multiple case labels to be associated with a common action. However, the same result can be achieved by specifying a single case label with a list of case constants, thereby associating the case constants with a common action.

Second, the action that can be associated with the case labels in switch rules is restricted. The switch statement with the colon notation allows a group of statements, but the switch statement with the arrow notation only allows the following actions to be associated with case labels:

By far, the canonical action of a case label in a switch rule is an expression statement. Such an expression statement is always terminated by a semicolon (;). Typically, the value returned by the expression statement is discarded. In the examples below, what is important is the side effect of evaluating the expression statements.

Click here to view code image


case PASSED -> ++numbersPassed;
case FAILED -> ++numbersFailed;

A block of statements can be used if program logic should be refined.

Click here to view code image


case ALARM ->  { soundTheAlarm();
                 callTheFireDepartment(); }

The switch rule below throws an exception when the value of the selector expression does not match any case constants:

Click here to view code image


default -> throw new IllegalArgumentException(“Not a valid value”);

Third, the execution of the switch rules is mutually exclusive (Figure 4.5). Once the action in the switch rule has completed execution, the execution of the switch statement terminates. This is illustrated in Figure 4.5 where only one expression statement is executed, after which the switch statement also terminates. There is no fall-through and the break statement is not necessary.

Figure 4.5 Activity Diagram for the switch Statement with the Arrow Notation

Example 4.3 is a refactoring of Example 4.2 with a switch statement with the arrow notation. At (2), (3), (4), and (8), the action executed is an expression statement, whereas at (5), the action executed is a block. Using switch rules results in compact and elegant code that also improves the readability of the switch statement.

Example 4.3 Nested switch Statements with the Arrow Notation

Click here to view code image

public class SeasonsII {
  public static void main(String[] args) {
    int monthNumber = 11;
    switch(monthNumber) {                                             // (1) Outer
      case 12, 1,  2 -> System.out.println(“Snow in the winter.”);    // (2)
      case 3,  4,  5 -> System.out.println(“Green grass in the spring.”);   // (3)
      case 6,  7,  8 -> System.out.println(“Sunshine in the summer.”);      // (4)
      case 9, 10, 11 -> {                                             // (5)
        switch(monthNumber) { // Nested switch                           (6) Inner
          case 10 -> System.out.println(“Halloween.”);
          case 11 -> System.out.println(“Thanksgiving.”);
        }
        // Always printed for case constants 9, 10, 11:
        System.out.println(“Yellow leaves in the fall.”);             // (7)
      }
      default -> throw new IllegalArgumentException(monthNumber +
                                            ” is not a valid month.”);// (8)
    }
  }
}

Output from the program:

Click here to view code image

Thanksgiving.
Yellow leaves in the fall.

Multidimensional Arrays – Declarations

Multidimensional Arrays

Since an array element can be an object reference and arrays are objects, array elements can themselves refer to other arrays. In Java, an array of arrays can be defined as follows:

Click here to view code image

element_type
[][]…[]
array_name;

or

Click here to view code image

element_type array_name
[][]…[];

In fact, the sequence of square bracket pairs, [], indicating the number of dimensions, can be distributed as a postfix to both the element type and the array name. Arrays of arrays are often called multidimensional arrays.

The following declarations are all equivalent:

Click here to view code image

int[][] mXnArray;      // two-dimensional array
int[]   mXnArray[];    // two-dimensional array
int     mXnArray[][];  // two-dimensional array

It is customary to combine the declaration with the construction of the multidimensional array.

Click here to view code image

int[][] mXnArray = new int[4][5];    // 4 x 5 matrix of ints

The previous declaration constructs an array mXnArray of four elements, where each element is an array (row) of five int values. The concept of rows and columns is often used to describe the dimensions of a two-dimensional array, which is often called a matrix. However, such an interpretation is not dictated by the Java language.

Each row in the previous matrix is denoted by mXnArray[i], where 0 ≤ i < 4. Each element in the ith row, mXnArray[i], is accessed by mXnArray[i][j], where 0 ≤ j < 5. The number of rows is given by mXnArray.length, in this case 4, and the number of values in the ith row is given by mXnArray[i].length, in this case 5 for all the rows, where 0 ≤ i < 4.

Multidimensional arrays can also be constructed and explicitly initialized using the array initializers discussed for simple arrays. Note that each row is an array that uses an array initializer to specify its values:

Click here to view code image

double[][] identityMatrix = {
  {1.0, 0.0, 0.0, 0.0 }, // 1. row
  {0.0, 1.0, 0.0, 0.0 }, // 2. row
  {0.0, 0.0, 1.0, 0.0 }, // 3. row
  {0.0, 0.0, 0.0, 1.0 }  // 4. row
}; // 4 x 4 floating-point matrix

Arrays in a multidimensional array need not have the same length; in which case, they are called ragged arrays. The array of arrays pizzaGalore in the following code has five rows; the first four rows have different lengths but the fifth row is left unconstructed:

Click here to view code image

Pizza[][] pizzaGalore = {
  { new Pizza(), null, new Pizza() },    // 1. row is an array of 3 elements.
  { null, new Pizza()},                  // 2. row is an array of 2 elements.
  new Pizza[1],                          // 3. row is an array of 1 element.
  {},                                    // 4. row is an array of 0 elements.
  null                                   // 5. row is not constructed.
};

When constructing multidimensional arrays with the new operator, the length of the deeply nested arrays may be omitted. In such a case, these arrays are left unconstructed. For example, an array of arrays to represent a room (defined by class HotelRoom) on a floor in a hotel on a street in a city can have the type HotelRoom[][][][]. From left to right, the square brackets represent indices for street, hotel, floor, and room, respectively. This four-dimensional array of arrays can be constructed piecemeal, starting with the leftmost dimension and proceeding to the rightmost successively.

Click here to view code image

HotelRoom[][][][] rooms = new HotelRoom[10][5][][];  // Just streets and hotels.

The preceding declaration constructs the array of arrays rooms partially with 10 streets, where each street has five hotels. Floors and rooms can be added to a particular hotel on a particular street:

Click here to view code image

rooms[0][0]       = new HotelRoom[3][]; // 3 floors in 1st hotel on 1st street.
rooms[0][0][0]    = new HotelRoom[8];   // 8 rooms on 1st floor in this hotel.
rooms[0][0][0][0] = new HotelRoom();    // Initializes 1st room on this floor.

The next code snippet constructs an array of arrays matrix, where the first row has one element, the second row has two elements, and the third row has three elements. Note that the outer array is constructed first. The second dimension is constructed in a loop that constructs the array in each row. The elements in the multidimensional array will be implicitly initialized to the default double value (0.0D). In Figure 3.1, the array of arrays matrix is depicted after the elements have been explicitly initialized.

Click here to view code image

double[][] matrix = new double[3][];      // (1) Number of rows.

for (int i = 0; i < matrix.length; ++i)
  matrix[i] = new double[i + 1];          // Construct a row.

Figure 3.1 Array of Arrays

The type of the variable matrix is double[][] at (1), a two-dimensional array of double values. The type of the variable matrix[i] (where 0 ≤ i< matrix.length) is double[], a one-dimensional array of double values. The type of the variable matrix[i][j] (where 0 ≤ i< matrix.length and 0 ≤ j< matrix[i].length) is double, a simple variable of type double.

Two other ways of initializing such an array of arrays are shown next. The first approach uses array initializers, and the second uses an anonymous array of arrays.

Click here to view code image

double[][] matrix2 = {    // (2) Using array initializers.
  {1.0},                  // 1. row
  {1.0, 2.0},             // 2. row
  {1.0, 2.0, 3.0}         // 3. row
};

double[][] matrix3 = new double[][] { // (3) Using an anonymous array of arrays.
  {1.0},                  // 1. row
  {1.0, 2.0},             // 2. row
  {1.0, 2.0, 1.0}         // 3. row
};

Nested loops are a natural match for manipulating multidimensional arrays. In Example 3.9, a rectangular 4 × 3 int matrix is declared and constructed at (1). The program finds the minimum value in the matrix. The outer loop at (2) iterates over the rows (mXnArray[i], where 0 ≤ i< mXnArray.length), and the inner loop at (3) iterates over the elements in each row in turn (mXnArray[i][j], where 0 ≤ j< mXnArray[i].length). The outer loop is executed mXnArray.length times, or four times, and the inner loop is executed (mXnArray.length) × (mXnArray[i].length), or 12 times, since all rows have the same length 3.

The for(:) loop also provides a safe and convenient way of iterating over an array. Several examples of its use are provided in §4.8, p. 176.

Example 3.9 Using Multidimensional Arrays

Click here to view code image

public class MultiArrays {
  public static void main(String[] args) {
    // Declare and construct the M X N matrix.
    int[][] mXnArray = {                                           // (1)
        {16,  7, 12}, // 1. row
        { 9, 20, 18}, // 2. row
        {14, 11,  5}, // 3. row
        { 8,  5, 10}  // 4. row
    }; // 4 x 3 int matrix
    // Find the minimum value in an M X N matrix:
    int min = mXnArray[0][0];
    for (int i = 0; i < mXnArray.length; ++i)                      // (2)
      // Find min in mXnArray[i], in the row given by index i:
      for (int j = 0; j < mXnArray[i].length; ++j)                 // (3)
        min = Math.min(min, mXnArray[i][j]);
    System.out.println(“Minimum value: ” + min);
  }
}”

Output from the program: Minimum value: 5