Why 2D arrays?
2D arrays are perfect for grids: game boards, seating charts, pixel matrices, and more. In Java, a 2D array is actually an array of arrays. That means rows can have different lengths (ragged arrays) and knowing how to navigate them is key.
Visual model (rows x columns):
[ [a00, a01, a02],
[a10, a11, a12],
[a20, a21, a22] ]
Declaring, creating, and initializing
- Fixed-size rectangular matrix
int[][] grid = new int[3][4]; // 3 rows, 4 columns; all values default to 0
grid[1][2] = 7; // row 1, column 2
- Literal initializer
int[][] scores = {
{10, 20, 30},
{15, 25, 35}
};
- Ragged (jagged) array (rows can differ in length)
int[][] triangle = new int[3][];
triangle[0] = new int[1];
triangle[1] = new int[2];
triangle[2] = new int[3];
Lengths you must know
- Number of rows:
grid.length - Number of columns in row i:
grid[i].length
Only use grid[0].length if you are sure the array has at least one row and it’s rectangular.
Traversing a 2D array
- Classic nested loops (row-major order):
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
System.out.print(grid[i][j] + " ");
}
System.out.println();
}
- Enhanced for-each loops:
for (int[] row : grid) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
- Column-major traversal (useful for column operations):
int rows = grid.length;
int cols = rows == 0 ? 0 : grid[0].length; // only if rectangular
for (int j = 0; j < cols; j++) {
for (int i = 0; i < rows; i++) {
System.out.print(grid[i][j] + " ");
}
System.out.println();
}
Printing 2D arrays cleanly
Arrays.toString(grid) will not print values for 2D arrays. Use:
import java.util.Arrays;
System.out.println(Arrays.deepToString(grid));
Or a helper:
static void printMatrix(int[][] m) {
for (int[] row : m) {
System.out.println(Arrays.toString(row));
}
}
Practical utilities you can reuse
- Fill every cell with a value:
import java.util.Arrays;
static void fill(int[][] m, int value) {
for (int[] row : m) Arrays.fill(row, value);
}
- Sum of a row / column:
static int sumRow(int[][] m, int r) {
int s = 0;
for (int v : m[r]) s += v;
return s;
}
static int sumCol(int[][] m, int c) {
int s = 0;
for (int i = 0; i < m.length; i++) {
if (c < m[i].length) s += m[i][c]; // safe for ragged arrays
}
return s;
}
- Search for a value (return position or -1, -1):
static int[] find(int[][] m, int target) {
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[i].length; j++) {
if (m[i][j] == target) return new int[]{i, j};
}
}
return new int[]{-1, -1};
}
- Transpose (swap rows and columns; requires rectangular input):
static int[][] transpose(int[][] m) {
int rows = m.length;
int cols = rows == 0 ? 0 : m[0].length;
int[][] t = new int[cols][rows];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
t[j][i] = m[i][j];
}
}
return t;
}
- Matrix addition (same dimensions):
static int[][] add(int[][] a, int[][] b) {
int r = a.length, c = r == 0 ? 0 : a[0].length;
int[][] out = new int[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
out[i][j] = a[i][j] + b[i][j];
}
}
return out;
}
- Matrix multiplication (a[r x m] * b[m x c] = out[r x c]):
static int[][] multiply(int[][] a, int[][] b) {
int r = a.length;
int m = r == 0 ? 0 : a[0].length;
int c = b.length == 0 ? 0 : b[0].length;
int[][] out = new int[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
int sum = 0;
for (int k = 0; k < m; k++) {
sum += a[i][k] * b[k][j];
}
out[i][j] = sum;
}
}
return out;
}
Reading a 2D array from input (Scanner)
import java.util.*;
public class ReadMatrixDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int rows = sc.nextInt();
int cols = sc.nextInt();
int[][] m = new int[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m[i][j] = sc.nextInt();
}
}
System.out.println(Arrays.deepToString(m));
}
}
Common pitfalls (and how to fix them)
- Index out of bounds
- Cause: using
i <= m.lengthorj <= m[i].lengthin loops. - Fix: use
<(strictly less than), not<=.
- Assuming rectangular shape
- Cause: using
m[0].lengthin a ragged array. - Fix: always use
m[i].lengthfor the current row, or validate rows are equal length first.
- Arrays.fill on the outer array
int[][] m = new int[3][];
Arrays.fill(m, new int[4]); // BAD: all rows point to the same array!
m[0][0] = 1; // now m[1][0] is also 1
- Fix: fill each row separately with a new array.
int[][] m = new int[3][4]; // OK
// or
for (int i = 0; i < m.length; i++) m[i] = new int[4];
- Shallow copies
int[][] a = {{1,2},{3,4}};
int[][] b = a.clone(); // shallow: rows are shared!
a[0][0] = 99; // b[0][0] becomes 99 too
- Fix: deep copy
static int[][] deepCopy(int[][] m) {
int[][] copy = new int[m.length][];
for (int i = 0; i < m.length; i++) copy[i] = m[i].clone();
return copy;
}
- Empty arrays
- Cause: calling
m[0].lengthwhenm.length == 0. - Fix: check if
m.length > 0first.
Quick practice prompts
- Count how many zeros are in a matrix.
- Compute the maximum value in each row and return it as a 1D array.
- Check if a matrix is symmetric (
m[i][j] == m[j][i]). - Rotate a square matrix 90° clockwise.
- Validate a Sudoku row/column/box using a 9x9 int array.
Cheat sheet
- Declare:
int[][] m; - Create:
m = new int[r][c]; - Rows:
m.length - Cols (row i):
m[i].length - Print:
Arrays.deepToString(m) - Traverse: nested loops over rows then columns
- Safe ragged handling: always use
m[i].length
With these patterns and utilities, you can confidently build and debug programs that use 2D arrays in Java.