Multidimensional and Jagged Arrays in Java

Java has no true two dimensional array. It has arrays of arrays, which is what makes jagged shapes possible.

The key idea

Java does not have a rectangular multidimensional array type. A int[][] is an array whose elements are themselves arrays. Every rule about arrays applies at each level, and that single fact explains all the behaviour below.

Declaring and creating

int[][] grid = new int[3][4];      // 3 rows, each row a new int[4]

int[][] table = {
    {1, 2, 3},
    {4, 5, 6}
};

System.out.println(table.length);      // 2 - number of rows
System.out.println(table[0].length);   // 3 - length of the first row

Traversing

int[][] sales = {
    {120, 340, 210},
    {90, 150, 400}
};

int total = 0;
for (int row = 0; row < sales.length; row++) {
    for (int col = 0; col < sales[row].length; col++) {   // per row length
        total += sales[row][col];
    }
}

for (int[] row : sales) {          // the enhanced form nests the same way
    for (int value : row) {
        total += value;
    }
}
Always use sales[row].length for the inner bound rather than sales[0].length. The rows are independent arrays and may differ in length.

Jagged arrays

int[][] triangle = new int[4][];    // rows allocated, columns not

for (int row = 0; row < triangle.length; row++) {
    triangle[row] = new int[row + 1];    // each row a different length
    for (int col = 0; col <= row; col++) {
        triangle[row][col] = (col == 0 || col == row) ? 1 : 0;
    }
}

Leaving the second dimension empty is legal and creates an array of null references, each waiting for its own row. This is exactly why the shape can be irregular.

Printing

import java.util.Arrays;

int[][] table = {{1, 2}, {3, 4}};

System.out.println(Arrays.toString(table));       // shows two array references
System.out.println(Arrays.deepToString(table));   // [[1, 2], [3, 4]]

The same distinction applies to comparison: Arrays.equals compares the top level references, while Arrays.deepEquals compares the contents at every level.

A worked example: matrix addition

public static int[][] add(int[][] a, int[][] b) {
    if (a.length != b.length) {
        throw new IllegalArgumentException("Row counts differ");
    }
    int[][] result = new int[a.length][];

    for (int row = 0; row < a.length; row++) {
        if (a[row].length != b[row].length) {
            throw new IllegalArgumentException("Row " + row + " lengths differ");
        }
        result[row] = new int[a[row].length];
        for (int col = 0; col < a[row].length; col++) {
            result[row][col] = a[row][col] + b[row][col];
        }
    }
    return result;
}

Three dimensions and beyond

int[][][] cube = new int[2][3][4];
System.out.println(cube[1][2][3]);   // 0

The nesting continues indefinitely, but beyond two dimensions a small class or record usually models the data better than an index soup.

Common mistakes

  • Using grid[0].length as the inner bound on a jagged array and reading out of range.
  • Swapping the row and column index. grid[row][col] is the conventional order.
  • Forgetting to allocate the inner arrays after new int[4][], which gives a NullPointerException.
  • Using Arrays.toString where deepToString was needed.
  • Copying with Arrays.copyOf and assuming the rows were copied too. They are shared, because only the outer array is duplicated.

Best practices

  • Name the loop variables row and col rather than i and j when the meaning is positional.
  • Validate the shape at the start of a method that takes a matrix.
  • For a genuinely rectangular grid, consider a single flat array with computed indices, which is friendlier to the cache.
  • Prefer a record or a small class once each cell means more than a number.

Practice

  1. Build a jagged array where row n holds the first n multiples of 3, and print it with deepToString.
  2. Write a method that transposes a rectangular int[][].
  3. Why does new int[3][] compile while new int[][3] does not?
  4. Predict the output of Arrays.equals(a, b) for two separate arrays with identical contents at both levels, and then of Arrays.deepEquals(a, b).
  5. Write a method that returns the sum of the main diagonal of a square matrix, validating that it is square.

Conclusion

Treat every level as an ordinary array and multidimensional arrays lose their mystery. Rows are independent objects, which is why lengths can differ and why deep copies and deep comparisons need their own methods.

Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All Java notes →
Java

Arrays in Java

An array is a fixed size object holding elements of one type, indexed from zero, with the length fixed at creation.

Read more
Java

Strings in Java

String is an immutable object with a shared literal pool, and both facts explain how comparison, concatenation and performance behave.

Read more
Java

Introduction to Java

Java is a statically typed, object oriented language that compiles to bytecode and runs on a virtual machine, which is what makes it portable.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.