JB Header

Multi-Dimensional and Jagged Arrays in Java

Introduction Many kinds of data come in rows and columns - a seating plan, a game board, a timetable, the pixels of an image. Java represents them with multi-dimensional arrays. This tutorial explains multi-dimensional and jagged arrays in Java with examples. We will start with two-dimensional arrays - how to declare, create and initialize them. We will then go through them with nested loops, and see how they are really stored - as arrays of arrays. Next we will build jagged arrays, whose rows have different lengths. Lastly, we will look at three-dimensional arrays and at common pitfalls.

(Note - This tutorial builds on Java Arrays: Declare, Create and InitializeClick to read tutorial: Java Arrays Tutorial: Declare, Create and Initialize.) Two-dimensional arrays A two-dimensional (2D) array has two indexes - a row and a column. Its type has two pairs of brackets, such as int[][].
Declaring and creating 2D arrays
int[][] grid = new int[3][4];         // 3 rows, 4 columns, all elements 0

int[][] matrix = {                    // initialized with values: 2 rows, 3 columns
  {1, 2, 3},
  {4, 5, 6}
};
  • grid[1][2] is the element in row 1, column 2. Both indexes start at 0.
  • grid.length is the number of rows, and grid[0].length is the number of columns in row 0.
  • As with one-dimensional arrays, the elements of new int[3][4] start at their default value, 0.
Working with a 2D array
//Matrix.java
public class Matrix {
  public static void main(String[] args) {
    int[][] sales = {
      {120, 95, 140},     // store 0: Jan, Feb, Mar
      {80, 110, 105},     // store 1
      {150, 160, 155}     // store 2
    };
    System.out.println("Rows: " + sales.length + ", columns: " + sales[0].length);
    System.out.println("Store 1 in Feb: " + sales[1][1]);
    sales[1][1] = 115;

    System.out.printf("%-8s%5s%5s%5s%7s%n", "", "Jan", "Feb", "Mar", "Total");
    for (int store = 0; store < sales.length; store++) {
      int total = 0;
      System.out.printf("%-8s", "Store " + store);
      for (int month = 0; month < sales[store].length; month++) {
        System.out.printf("%5d", sales[store][month]);
        total += sales[store][month];
      }
      System.out.printf("%7d%n", total);
    }

    int[] monthTotals = new int[3];
    for (int[] row : sales) {
      for (int month = 0; month < row.length; month++) {
        monthTotals[month] += row[month];
      }
    }
    System.out.println("Month totals: " + java.util.Arrays.toString(monthTotals));
  }
}
 OUTPUT of the above code
Rows: 3, columns: 3
Store 1 in Feb: 110
          Jan  Feb  Mar  Total
Store 0   120   95  140    355
Store 1    80  115  105    300
Store 2   150  160  155    465
Month totals: [350, 370, 400]
Explanation of the code
  • The outer loop goes through the rows, and the inner loop through the columns of each row - the nested for loopsClick to read tutorial: Java for Loop Tutorial with Examples pattern. Row totals are added up inside the outer loop.
  • The inner loop uses sales[store].length rather than a fixed 3, so it works even when rows have different lengths.
  • An enhanced for loop over a 2D array gives each row, which is itself an int[].
Arrays of arrays Java does not really have rectangular 2D arrays. An int[][] is an array whose elements are references to int[] arrays - one array for each row. This is why grid[1] on its own is valid: it is row 1, a whole int[].
A 2D array is an array of row arrays
//ArrayOfArrays.java
import java.util.Arrays;

public class ArrayOfArrays {
  public static void main(String[] args) {
    int[][] grid = new int[3][4];
    int[] row1 = grid[1];               // a reference to row 1
    row1[2] = 7;
    System.out.println("grid[1][2] = " + grid[1][2]);

    grid[0] = new int[] {9, 9};         // replace a whole row - with a shorter one!
    for (int[] row : grid) {
      System.out.println(Arrays.toString(row));
    }
    System.out.println(Arrays.deepToString(grid));
  }
}
 OUTPUT of the above code
grid[1][2] = 7
[9, 9]
[0, 0, 7, 0]
[0, 0, 0, 0]
[[9, 9], [0, 0, 7, 0], [0, 0, 0, 0]]
Explanation of the code
  • row1 refers to the same row array as grid[1], so setting row1[2] changed the grid.
  • A whole row can be replaced - even with an array of a different length. The "rectangular" array is now ragged.
  • Arrays.toString() prints one level only. For nested arrays, Arrays.deepToString() prints every level.
Jagged arrays A jagged (ragged) array is a multi-dimensional array whose rows have different lengths. Create it by giving only the number of rows, and then creating each row separately. Jagged arrays save memory when rows naturally differ in size - such as the days of each month, or the rows of Pascal's triangle.
A jagged array - Pascal's triangle
//PascalTriangle.java
public class PascalTriangle {
  public static void main(String[] args) {
    int rows = 6;
    int[][] triangle = new int[rows][];          // rows created, columns not yet
    for (int r = 0; r < rows; r++) {
      triangle[r] = new int[r + 1];              // row r has r + 1 elements
      triangle[r][0] = 1;
      triangle[r][r] = 1;
      for (int c = 1; c < r; c++) {
        triangle[r][c] = triangle[r - 1][c - 1] + triangle[r - 1][c];
      }
    }

    for (int[] row : triangle) {
      System.out.print(" ".repeat((rows - row.length) * 2));
      for (int value : row) {
        System.out.printf("%4d", value);
      }
      System.out.println();
    }

    String[][] teams = {
      {"Tom", "Harry"},
      {"Ethan"},
      {"Nancy", "Deborah", "Sam"}
    };
    for (int t = 0; t < teams.length; t++) {
      System.out.println("Team " + t + " size: " + teams[t].length);
    }
  }
}
 OUTPUT of the above code
             1
           1   1
         1   2   1
       1   3   3   1
     1   4   6   4   1
   1   5  10  10   5   1
Team 0 size: 2
Team 1 size: 1
Team 2 size: 3
Explanation of the code
  • new int[rows][] creates the outer array only. Until each row is assigned, triangle[r] is null.
  • Each row is created with its own length, r + 1. Each inner value is the sum of the two values above it.
  • An initializer with rows of different lengths, like teams, also creates a jagged array.
Three-dimensional arrays Arrays can have any number of dimensions. A 3D array is an array of 2D arrays - for example, a building's seats indexed by floor, row and seat number.
A three-dimensional array
//Cinema3D.java
public class Cinema3D {
  public static void main(String[] args) {
    boolean[][][] booked = new boolean[2][3][4];   // 2 screens, 3 rows, 4 seats
    booked[0][1][2] = true;
    booked[1][0][0] = true;
    booked[1][2][3] = true;

    int count = 0;
    for (boolean[][] screen : booked) {
      for (boolean[] row : screen) {
        for (boolean seat : row) {
          if (seat) {
            count++;
          }
        }
      }
    }
    System.out.println("Seats: " + 2 * 3 * 4 + ", booked: " + count);
  }
}
 OUTPUT of the above code
Seats: 24, booked: 3
Arrays with more than three dimensions are rare. When data has that many dimensions, a class which describes it - such as a Seat with a screen, row and number - is usually clearer. Common pitfalls
  • Mixing up rows and columns: by convention the first index is the row. Keep to it, and name loop variables row and col rather than i and j.
  • Assuming every row has the same length: loop with array[row].length, not array[0].length, in case the array is jagged.
  • Using rows that were never created: after new int[3][], using grid[0][0] throws a NullPointerException until row 0 is created.
  • Shallow copies: grid.clone() copies only the outer array - both copies share the same row arrays. Copy each row to get an independent copy.
Summary In this tutorial we first declared, created and initialized two-dimensional arrays, and processed one with nested loops to calculate row and column totals. We then saw that a 2D array is really an array of row arrays, so rows can be shared, replaced and printed with Arrays.deepToString(). Next we built jagged arrays, whose rows have different lengths, including Pascal's triangle. We then used a three-dimensional array, and lastly went through common pitfalls. In the next tutorial, we will use the many helpful methods of the java.util.Arrays classClick to read tutorial: Java Arrays Class: sort, binarySearch, fill, copyOf.