Java Multi-dimensional Arrays
Java Multi-dimensional Arrays
A one-dimensional array is a list — a row of values. A two-dimensional array is a table — rows and columns. A three-dimensional array is a cube — layers of tables. Multi-dimensional arrays in Java are simply arrays of arrays, and that mental model explains every operation you will ever perform on them.
When you see a seating chart, a cricket scorecard with batsmen across multiple innings, or a monthly attendance register with students and dates — you are looking at data that naturally lives in a two-dimensional structure. Multi-dimensional arrays are Java's way to represent and work with exactly that kind of data.
How 2D Arrays Work
A 2D array in Java is an array where each element is itself a 1D array. The outer array holds rows. Each row holds the actual values.
int[][] marks = new int[3][4]
| |
rows columns
Visualised as a grid:
col 0 col 1 col 2 col 3
row 0 [ 85 ] [ 90 ] [ 78 ] [ 92 ]
row 1 [ 76 ] [ 88 ] [ 95 ] [ 71 ]
row 2 [ 65 ] [ 83 ] [ 79 ] [ 97 ]
Accessing:
marks[0][0] = 85 (row 0, col 0)
marks[1][2] = 95 (row 1, col 2)
marks[2][3] = 97 (row 2, col 3)
marks.length = 3 (number of rows)
marks[0].length = 4 (number of columns in row 0)
Declaring, Creating, and Initialising 2D Arrays
1// File: TwoDArrayBasics.java
2
3import java.util.Arrays;
4
5public class TwoDArrayBasics {
6
7 public static void main(String[] args) {
8
9 // Way 1 — declare size, fill later
10 // JVM fills all slots with 0 (for int)
11 int[][] grid = new int[3][4];
12 grid[0][0] = 1; grid[0][1] = 2; grid[0][2] = 3; grid[0][3] = 4;
13 grid[1][0] = 5; grid[1][1] = 6; grid[1][2] = 7; grid[1][3] = 8;
14 grid[2][0] = 9; grid[2][1] = 10; grid[2][2] = 11; grid[2][3] = 12;
15
16 System.out.println("Way 1 (fill later):");
17 System.out.println(" Rows : " + grid.length);
18 System.out.println(" Columns : " + grid[0].length);
19 System.out.println(" grid[1][2] = " + grid[1][2]);
20
21 // Way 2 — inline initialiser (most readable)
22 int[][] matrix = {
23 {1, 2, 3},
24 {4, 5, 6},
25 {7, 8, 9}
26 };
27 System.out.println("\nWay 2 (inline initialiser):");
28 System.out.println(" Row 0: " + Arrays.toString(matrix[0]));
29 System.out.println(" Row 1: " + Arrays.toString(matrix[1]));
30 System.out.println(" Row 2: " + Arrays.toString(matrix[2]));
31
32 // Way 3 — declare rows first, add columns separately
33 String[][] schedule = new String[5][];
34 schedule[0] = new String[]{"Math", "Science"};
35 schedule[1] = new String[]{"English", "Hindi", "PE"};
36 schedule[2] = new String[]{"Math", "Computer", "Art"};
37 schedule[3] = new String[]{"Science", "English"};
38 schedule[4] = new String[]{"Hindi", "Math", "Science", "PE"};
39
40 System.out.println("\nWay 3 (jagged — rows added separately):");
41 for (int i = 0; i < schedule.length; i++) {
42 System.out.println(" Day " + (i + 1) + ": " + Arrays.toString(schedule[i]));
43 }
44 }
45}Output:
Way 1 (fill later):
Rows : 3
Columns : 4
grid[1][2] = 7
Way 2 (inline initialiser):
Row 0: [1, 2, 3]
Row 1: [4, 5, 6]
Row 2: [7, 8, 9]
Way 3 (jagged — rows added separately):
Day 1: [Math, Science]
Day 2: [English, Hindi, PE]
Day 3: [Math, Computer, Art]
Day 4: [Science, English]
Day 5: [Hindi, Math, Science, PE]
Way 3 creates a jagged array — a 2D array where rows have different lengths. The outer array has five slots, each pointing to a String[] of its own size. Java allows this because the outer array stores references to row arrays — each row array can be any length.
Traversing a 2D Array
The standard pattern is two nested loops — outer loop for rows, inner loop for columns.
1// File: TwoDTraversalDemo.java
2
3public class TwoDTraversalDemo {
4
5 public static void main(String[] args) {
6
7 int[][] scores = {
8 {72, 85, 90},
9 {88, 61, 78},
10 {95, 83, 70},
11 {65, 91, 77}
12 };
13
14 // Method 1 — nested for loop (use when index is needed)
15 System.out.println("Nested for loop (with indices):");
16 for (int row = 0; row < scores.length; row++) {
17 for (int col = 0; col < scores[row].length; col++) {
18 System.out.printf(" scores[%d][%d] = %d%n", row, col, scores[row][col]);
19 }
20 }
21
22 System.out.println();
23
24 // Method 2 — nested for-each (cleaner, no index management)
25 System.out.println("Nested for-each (values only):");
26 int total = 0;
27 for (int[] row : scores) {
28 for (int score : row) {
29 total += score;
30 System.out.print(score + " ");
31 }
32 System.out.println();
33 }
34 System.out.println("Total of all scores: " + total);
35
36 System.out.println();
37
38 // Method 3 — print each row using Arrays.toString()
39 System.out.println("Row-by-row print:");
40 for (int[] row : scores) {
41 System.out.println(" " + java.util.Arrays.toString(row));
42 }
43 }
44}Output:
Nested for loop (with indices):
scores[0][0] = 72
scores[0][1] = 85
scores[0][2] = 90
scores[1][0] = 88
...
Nested for-each (values only):
72 85 90
88 61 78
95 83 70
65 91 77
Total of all scores: 1055
Row-by-row print:
[72, 85, 90]
[88, 61, 78]
[95, 83, 70]
[65, 91, 77]
scores[row].length is used in the inner loop — not scores[0].length — because jagged arrays can have different column counts per row. Using scores[row].length always works correctly for both regular and jagged arrays.
Matrix Operations — Addition and Transpose
Two-dimensional arrays map directly to matrices in mathematics. Matrix addition and transposition are the most common operations.
1// File: MatrixOperations.java
2
3import java.util.Arrays;
4
5public class MatrixOperations {
6
7 // Print a 2D array as a formatted grid
8 public static void printMatrix(String label, int[][] m) {
9 System.out.println(label + ":");
10 for (int[] row : m) {
11 System.out.print(" [ ");
12 for (int val : row) System.out.printf("%4d ", val);
13 System.out.println("]");
14 }
15 System.out.println();
16 }
17
18 // Add two matrices of the same dimensions
19 public static int[][] addMatrices(int[][] a, int[][] b) {
20 int rows = a.length;
21 int cols = a[0].length;
22 int[][] result = new int[rows][cols];
23 for (int i = 0; i < rows; i++) {
24 for (int j = 0; j < cols; j++) {
25 result[i][j] = a[i][j] + b[i][j];
26 }
27 }
28 return result;
29 }
30
31 // Transpose: rows become columns, columns become rows
32 public static int[][] transpose(int[][] m) {
33 int rows = m.length;
34 int cols = m[0].length;
35 int[][] result = new int[cols][rows]; // note: dimensions swap
36 for (int i = 0; i < rows; i++) {
37 for (int j = 0; j < cols; j++) {
38 result[j][i] = m[i][j]; // swap indices
39 }
40 }
41 return result;
42 }
43
44 public static void main(String[] args) {
45
46 int[][] matA = {
47 {1, 2, 3},
48 {4, 5, 6}
49 };
50
51 int[][] matB = {
52 {7, 8, 9},
53 {10, 11, 12}
54 };
55
56 printMatrix("Matrix A", matA);
57 printMatrix("Matrix B", matB);
58 printMatrix("A + B", addMatrices(matA, matB));
59 printMatrix("Transpose of A", transpose(matA));
60 }
61}Output:
Matrix A:
[ 1 2 3 ]
[ 4 5 6 ]
Matrix B:
[ 7 8 9 ]
[ 10 11 12 ]
A + B:
[ 8 10 12 ]
[ 14 16 18 ]
Transpose of A:
[ 1 4 ]
[ 2 5 ]
[ 3 6 ]
Transposing a 2×3 matrix gives a 3×2 matrix — rows and columns swap. This is why the result array is declared new int[cols][rows] — dimensions are reversed.
Jagged Arrays — When Rows Have Different Lengths
Regular 2D arrays have equal column counts in every row. Jagged arrays let each row have its own length — useful when the data itself is irregular.
1// File: JaggedArrayDemo.java
2
3public class JaggedArrayDemo {
4
5 public static void main(String[] args) {
6
7 // Pascal's Triangle — each row has one more element than the previous
8 int[][] pascal = new int[6][];
9
10 for (int row = 0; row < pascal.length; row++) {
11 pascal[row] = new int[row + 1]; // row 0 has 1 element, row 5 has 6
12 pascal[row][0] = 1;
13 pascal[row][row] = 1;
14 for (int col = 1; col < row; col++) {
15 pascal[row][col] = pascal[row - 1][col - 1] + pascal[row - 1][col];
16 }
17 }
18
19 System.out.println("Pascal's Triangle:");
20 for (int row = 0; row < pascal.length; row++) {
21 // Indent for visual triangle shape
22 System.out.print(" ".repeat((pascal.length - row - 1) * 2));
23 for (int val : pascal[row]) {
24 System.out.printf("%4d", val);
25 }
26 System.out.println();
27 }
28
29 System.out.println();
30
31 // Show that rows have different lengths
32 System.out.println("Row lengths:");
33 for (int i = 0; i < pascal.length; i++) {
34 System.out.println(" pascal[" + i + "].length = " + pascal[i].length);
35 }
36 }
37}Output:
Pascal's Triangle:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
Row lengths:
pascal[0].length = 1
pascal[1].length = 2
pascal[2].length = 3
pascal[3].length = 4
pascal[4].length = 5
pascal[5].length = 6
Pascal's Triangle is a textbook jagged array — each row has exactly one more element than the previous. A regular int[6][6] would work too but wastes the upper-right slots. Jagged arrays use memory only for what the data actually needs.
2D Array vs Jagged Array vs 3D Array — Comparison Table
| Aspect | Regular 2D Array | Jagged Array | 3D Array |
|---|---|---|---|
| Declaration | int[][] a = new int[3][4] | int[][] a = new int[3][] | int[][][] a = new int[2][3][4] |
| Column count | Same for every row | Can differ per row | Same per slice |
| Memory layout | Rectangular grid | Irregular — each row separate | Cube of values |
| Access syntax | a[row][col] | a[row][col] | a[layer][row][col] |
| Row length check | a[0].length works for all | Must use a[row].length | a[0][0].length |
| When to use | Tables, matrices, grids | Variable-length rows, triangles | 3D spatial data, time series grids |
| Memory efficiency | Fixed — may waste slots | Efficient — only allocates what is needed | Higher overhead |
| Common use case | Exam scores, seating chart | Pascal's Triangle, timetable | RGB images, 3D game maps |
Real-World Example 1 — Classroom Attendance Register
The Business Problem
A school teacher records daily attendance for a class over a school week. Each student either attended (1) or was absent (0) each day. The teacher wants to see the full attendance grid, calculate each student's attendance percentage, identify the most attended day, and flag students below 75% attendance. This is a classic 2D array problem — rows are students, columns are days.
1// File: AttendanceRegister.java
2
3public class AttendanceRegister {
4
5 private static final String[] STUDENT_NAMES = {
6 "Priya Sharma", "Rohan Mehta", "Sneha Rao",
7 "Karan Singh", "Ananya Iyer", "Deepak Joshi"
8 };
9
10 private static final String[] DAY_NAMES = {
11 "Mon", "Tue", "Wed", "Thu", "Fri"
12 };
13
14 // 1 = Present, 0 = Absent
15 // Rows = students, Columns = days
16 private static final int[][] ATTENDANCE = {
17 {1, 1, 1, 1, 1}, // Priya — all 5 days
18 {1, 0, 1, 1, 1}, // Rohan — absent Tuesday
19 {1, 1, 0, 0, 1}, // Sneha — absent Wed, Thu
20 {0, 1, 1, 1, 0}, // Karan — absent Mon, Fri
21 {1, 1, 1, 1, 1}, // Ananya — all 5 days
22 {0, 0, 1, 1, 0}, // Deepak — absent Mon, Tue, Fri
23 };
24
25 private static final int TOTAL_DAYS = DAY_NAMES.length;
26 private static final double MIN_ATTENDANCE = 75.0;
27
28 public static void main(String[] args) {
29
30 int students = STUDENT_NAMES.length;
31
32 // Print attendance grid
33 System.out.println("╔══ ATTENDANCE REGISTER ══════════════════╗");
34 System.out.printf("║ %-15s", "Student \\ Day");
35 for (String day : DAY_NAMES) System.out.printf(" %s", day);
36 System.out.printf(" %s %-6s ║%n", "Tot", "%");
37 System.out.println("╠═════════════════════════════════════════╣");
38
39 int[] dailyTotal = new int[TOTAL_DAYS]; // column totals for most-attended day
40
41 for (int s = 0; s < students; s++) {
42 int present = 0;
43 for (int d = 0; d < TOTAL_DAYS; d++) {
44 present += ATTENDANCE[s][d];
45 dailyTotal[d] += ATTENDANCE[s][d];
46 }
47 double pct = (present * 100.0) / TOTAL_DAYS;
48 String status = pct >= MIN_ATTENDANCE ? "OK " : "LOW ";
49
50 System.out.printf("║ %-15s", STUDENT_NAMES[s]);
51 for (int d = 0; d < TOTAL_DAYS; d++) {
52 System.out.printf(" %s", ATTENDANCE[s][d] == 1 ? "P" : "A");
53 }
54 System.out.printf(" %2d %5.1f%% %-4s║%n", present, pct, status);
55 }
56
57 // Daily totals row
58 System.out.println("╠═════════════════════════════════════════╣");
59 System.out.printf("║ %-15s", "Total Present");
60 int bestDay = 0;
61 for (int d = 0; d < TOTAL_DAYS; d++) {
62 System.out.printf(" %d", dailyTotal[d]);
63 if (dailyTotal[d] > dailyTotal[bestDay]) bestDay = d;
64 }
65 System.out.println(" ║");
66 System.out.printf("║ Best attended day: %-22s║%n", DAY_NAMES[bestDay]);
67 System.out.println("╚═════════════════════════════════════════╝");
68 }
69}Output:
╔══ ATTENDANCE REGISTER ══════════════════╗
║ Student \ Day Mon Tue Wed Thu Fri Tot % ║
╠═════════════════════════════════════════╣
║ Priya Sharma P P P P P 5 100.0% OK ║
║ Rohan Mehta P A P P P 4 80.0% OK ║
║ Sneha Rao P P A A P 3 60.0% LOW ║
║ Karan Singh A P P P A 3 60.0% LOW ║
║ Ananya Iyer P P P P P 5 100.0% OK ║
║ Deepak Joshi A A P P A 2 40.0% LOW ║
╠═════════════════════════════════════════╣
║ Total Present 4 4 5 5 4 ║
║ Best attended day: Wed ║
╚═════════════════════════════════════════╝
The 2D attendance grid maps perfectly to the problem — ATTENDANCE[student][day] reads naturally. The same array structure is used for row sums (per student) and column sums (per day) in the same traversal loop.
Real-World Example 2 — Cricket Scoreboard
The Business Problem
A cricket scorecard at a local match or IPL tracks runs scored by each batsman in each over. Rows are batsmen, columns are overs. The system calculates total runs per batsman, total runs per over, and the highest individual over score — a perfect 2D array problem that every Indian fresher immediately relates to.
1// File: CricketScoreboard.java
2
3public class CricketScoreboard {
4
5 private static final String[] BATSMEN = {
6 "Rohit Sharma", "Virat Kohli",
7 "Suryakumar", "Hardik Pandya"
8 };
9
10 // Rows = batsmen, Columns = overs (6 overs shown)
11 // Each cell = runs scored by that batsman in that over
12 private static final int[][] RUNS = {
13 {12, 8, 15, 6, 18, 10}, // Rohit Sharma
14 {6, 14, 9, 16, 5, 12}, // Virat Kohli
15 {0, 0, 8, 18, 22, 15}, // Suryakumar (came in later)
16 {0, 0, 0, 5, 12, 20}, // Hardik Pandya (came in over 4)
17 };
18
19 public static void main(String[] args) {
20
21 int batsmen = BATSMEN.length;
22 int totalOvers = RUNS[0].length;
23
24 System.out.println("╔═══════════════════════════════════════════════════╗");
25 System.out.println("║ CRICKET SCOREBOARD ║");
26 System.out.println("╠═══════════════════════════════════════════════════╣");
27 System.out.printf("║ %-16s", "Batsman");
28 for (int o = 1; o <= totalOvers; o++) {
29 System.out.printf(" Ov%d", o);
30 }
31 System.out.printf(" %s SR%n", "Total║");
32
33 System.out.println("╠═══════════════════════════════════════════════════╣");
34
35 int[] overTotals = new int[totalOvers];
36 int matchTotal = 0;
37 int highestRunsOvr = RUNS[0][0];
38 int hrBatsman = 0, hrOver = 0;
39
40 for (int b = 0; b < batsmen; b++) {
41 int batsmanTotal = 0;
42 int ballsFaced = 0;
43
44 System.out.printf("║ %-16s", BATSMEN[b]);
45 for (int o = 0; o < totalOvers; o++) {
46 int runs = RUNS[b][o];
47 System.out.printf(" %3d", runs);
48 batsmanTotal += runs;
49 overTotals[o] += runs;
50 matchTotal += runs;
51 if (runs > 0) ballsFaced += 6; // rough balls-per-over estimate
52
53 if (runs > highestRunsOvr) {
54 highestRunsOvr = runs;
55 hrBatsman = b;
56 hrOver = o + 1;
57 }
58 }
59 double strikeRate = ballsFaced > 0
60 ? (batsmanTotal * 100.0) / ballsFaced : 0;
61 System.out.printf(" %3d %.0f ║%n", batsmanTotal, strikeRate);
62 }
63
64 System.out.println("╠═══════════════════════════════════════════════════╣");
65 System.out.printf("║ %-16s", "Over Total");
66 for (int total : overTotals) System.out.printf(" %3d", total);
67 System.out.printf(" %3d ║%n", matchTotal);
68 System.out.println("╠═══════════════════════════════════════════════════╣");
69 System.out.printf("║ Match Total: %-5d ║%n", matchTotal);
70 System.out.printf("║ Best Over : Over %d by %s (%d runs) ║%n",
71 hrOver, BATSMEN[hrBatsman], highestRunsOvr);
72 System.out.println("╚═══════════════════════════════════════════════════╝");
73 }
74}Output:
╔═══════════════════════════════════════════════════╗
║ CRICKET SCOREBOARD ║
╠═══════════════════════════════════════════════════╣
║ Batsman Ov1 Ov2 Ov3 Ov4 Ov5 Ov6 Total SR║
╠═══════════════════════════════════════════════════╣
║ Rohit Sharma 12 8 15 6 18 10 69 192 ║
║ Virat Kohli 6 14 9 16 5 12 62 172 ║
║ Suryakumar 0 0 8 18 22 15 63 175 ║
║ Hardik Pandya 0 0 0 5 12 20 37 205 ║
╠═══════════════════════════════════════════════════╣
║ Over Total 18 22 32 45 57 57 231 ║
╠═══════════════════════════════════════════════════╣
║ Match Total: 231 ║
║ Best Over : Over 5 by Suryakumar (22 runs) ║
╚═══════════════════════════════════════════════════╝
Every cell RUNS[batsman][over] holds exactly one integer. The same nested loop computes both row totals (per batsman) and column totals (per over) in one pass. Tracking highestRunsOvr through both indices while traversing finds the best over across all batsmen simultaneously.
3D Arrays — A Brief Introduction
A 3D array adds one more dimension — think of it as a stack of 2D grids. int[layers][rows][cols] is the shape.
1// File: ThreeDArrayDemo.java
2
3public class ThreeDArrayDemo {
4
5 public static void main(String[] args) {
6
7 // Monthly sales data:
8 // Dimension 1 — months (3 months: Jan, Feb, Mar)
9 // Dimension 2 — products (3 products)
10 // Dimension 3 — weeks (4 weeks per month)
11 // Value = units sold
12
13 int[][][] salesData = {
14 // January — 3 products x 4 weeks
15 {{120, 135, 110, 145}, {80, 90, 75, 95}, {200, 180, 210, 220}},
16 // February
17 {{130, 140, 125, 150}, {85, 88, 80, 92}, {190, 195, 205, 215}},
18 // March
19 {{150, 160, 145, 170}, {90, 95, 88, 100},{220, 230, 225, 240}}
20 };
21
22 String[] months = {"January", "February", "March"};
23 String[] products = {"Product A", "Product B", "Product C"};
24
25 System.out.println("Monthly Sales Summary (units):\n");
26
27 for (int m = 0; m < salesData.length; m++) {
28 System.out.println("=== " + months[m] + " ===");
29
30 for (int p = 0; p < salesData[m].length; p++) {
31 int monthTotal = 0;
32 for (int w = 0; w < salesData[m][p].length; w++) {
33 monthTotal += salesData[m][p][w];
34 }
35 System.out.printf(" %-12s: %d units/month%n",
36 products[p], monthTotal);
37 }
38 System.out.println();
39 }
40
41 // Grand total across all dimensions
42 int grandTotal = 0;
43 for (int[][] month : salesData) {
44 for (int[] product : month) {
45 for (int units : product) {
46 grandTotal += units;
47 }
48 }
49 }
50 System.out.println("Grand total across 3 months: " + grandTotal + " units");
51 }
52}Output:
Monthly Sales Summary (units):
=== January ===
Product A : 510 units/month
Product B : 340 units/month
Product C : 810 units/month
=== February ===
Product A : 545 units/month
Product B : 345 units/month
Product C : 805 units/month
=== March ===
Product A : 625 units/month
Product B : 373 units/month
Product C : 915 units/month
Grand total across 3 months: 6268 units
Three nested for-each loops traverse a 3D array naturally — one per dimension. The shape is salesData[month][product][week]. 3D arrays are less common than 2D but appear in image processing (RGB channels), game grids (floor × row × column), and time-series data (month × category × week).
Best Practices
Use arr[row].length in the inner loop, not a hardcoded column count. For regular 2D arrays this always gives the right column count. For jagged arrays it is the only correct approach — each row can have a different number of columns. Using arr[0].length for all rows crashes on jagged arrays where later rows might be shorter.
Declare parallel 1D arrays alongside the 2D array rather than mixing concerns. STUDENT_NAMES[i] and ATTENDANCE[i] stay in sync by index without embedding names inside the 2D array. This separation keeps the data clean — names are metadata about rows, not part of the score data.
Use Arrays.deepToString() to print 2D arrays, not Arrays.toString(). Arrays.toString(marks) on a 2D array prints references — [[I@7852e922, ...]. Arrays.deepToString(marks) prints [[85, 90, 78], [76, 88, 95], ...]. This is the single most common printing mistake with multi-dimensional arrays.
Initialise 2D arrays close to their first use. Unlike 1D arrays, 2D array initialisers get long quickly. Declare, initialise, and use the array in the same block of code so the relationship between declaration and use stays visible.
Common Mistakes
Mistake 1 — Printing 2D Arrays Without deepToString()
1int[][] marks = {{85, 90}, {78, 95}};
2System.out.println(marks); // [[I@7852e922 — useless
3System.out.println(Arrays.toString(marks)); // [[I@1b6d3586, [I@4554617c] — still useless
4
5// Correct
6System.out.println(Arrays.deepToString(marks)); // [[85, 90], [78, 95]]Mistake 2 — NullPointerException From Uninitialised Rows in Jagged Arrays
1int[][] jagged = new int[3][]; // outer array allocated, rows are null
2jagged[0] = new int[]{1, 2};
3
4System.out.println(jagged[0][0]); // 1 — fine
5System.out.println(jagged[1][0]); // NullPointerException — jagged[1] is null
6// Fix: initialise every row before accessing itMistake 3 — Wrong Loop Condition for Inner Loop
1int[][] grid = {{1, 2, 3}, {4, 5}}; // jagged — row 1 has only 2 elements
2
3// Wrong — uses row 0's length for all rows
4for (int i = 0; i < grid.length; i++) {
5 for (int j = 0; j < grid[0].length; j++) { // grid[0].length = 3 — wrong for row 1
6 System.out.println(grid[i][j]);
7 }
8}
9// Throws ArrayIndexOutOfBoundsException when i=1, j=2
10
11// Correct — use grid[i].length
12for (int i = 0; i < grid.length; i++) {
13 for (int j = 0; j < grid[i].length; j++) {
14 System.out.println(grid[i][j]);
15 }
16}Mistake 4 — Confusing Row and Column Index Order
1// The declaration int[rows][cols] means:
2// First index = row, Second index = column
3int[][] seats = new int[3][5]; // 3 rows, 5 columns per row
4
5// Accessing the element at row 1, column 3:
6seats[1][3] = 1; // CORRECT
7seats[3][1] = 1; // ArrayIndexOutOfBoundsException — index 3 does not exist in 3-row arrayInterview Questions
Q1. What is a 2D array in Java and how does it work internally?
A 2D array in Java is an array of arrays. The outer array holds references to inner arrays — each inner array is a row. Declaring int[][] matrix = new int[3][4] creates an outer array of 3 slots, each pointing to a separate int[] of length 4. Because rows are independent objects, a jagged array — where each row has a different length — is valid. matrix.length gives the row count. matrix[i].length gives the column count for row i.
Q2. What is the difference between a regular 2D array and a jagged array?
A regular 2D array has the same number of columns in every row — declared as new int[rows][cols]. The JVM creates all rows with equal size. A jagged array is declared with only the row count — new int[rows][] — and each row is created separately with its own length. Rows can have different sizes. Pascal's Triangle, triangular matrices, and calendar data with variable days per month are natural uses for jagged arrays. Regular 2D arrays suit tables, grids, and matrices where every row has the same number of columns.
Q3. How do you traverse a 2D array in Java?
Two nested loops — outer for rows, inner for columns. Use for (int i = 0; i < arr.length; i++) for rows and for (int j = 0; j < arr[i].length; j++) for columns. Using arr[i].length in the inner loop rather than arr[0].length makes the traversal safe for jagged arrays. The nested for-each for (int[] row : arr) { for (int val : row) { ... } } is cleaner when index values are not needed.
Q4. What is Arrays.deepToString() and when do you need it?
Arrays.toString() works on 1D arrays — printing elements in [1, 2, 3] format. On a 2D array, it prints references to the inner arrays — [[I@7852e922, ...] — which is useless. Arrays.deepToString() recursively converts all levels to readable strings — [[85, 90], [78, 95]]. Always use Arrays.deepToString() when printing multi-dimensional arrays.
Q5. What exception is thrown when an invalid row or column index is used?
ArrayIndexOutOfBoundsException — the same exception as with 1D arrays. For a int[3][4] array, valid row indices are 0 to 2 and valid column indices are 0 to 3. Accessing arr[3][0] (row 3 does not exist) or arr[0][4] (column 4 does not exist) throws this exception. For jagged arrays, using arr[0].length as the inner loop limit for all rows throws the same exception when a later row is shorter.
Q6. How do you find the row sum and column sum of a 2D array?
Row sum: iterate each row with the inner loop, accumulate with a variable that resets before each row. Column sum: iterate with outer loop over columns and inner loop over rows — or accumulate a columnTotal[] array during normal row-first traversal. For a matrix m, rowSum[i] = sum of m[i][j] for all j and colSum[j] = sum of m[i][j] for all i. Both can be computed in a single pass of the standard nested loop.
FAQs
Can a 2D array in Java have rows of different lengths?
Yes — this is called a jagged array. Declare the outer array with only the row count (new int[rows][]) and initialise each row separately with its own new int[n]. The JVM treats each row as an independent 1D array. A jagged array is not a Java quirk — it is the natural result of 2D arrays being arrays of arrays.
Does Arrays.sort() work on 2D arrays?
Arrays.sort(arr) on a 2D array sorts the rows themselves — treating each inner array as a single element. This is rarely what you want. To sort by a specific column, you need a custom Comparator: Arrays.sort(arr, (row1, row2) -> row1[colIndex] - row2[colIndex]). To sort every row independently, loop over rows and call Arrays.sort(arr[i]) for each.
How much memory does a 2D array use?
A 2D array int[rows][cols] uses rows × cols × 4 bytes for the integer data (each int is 4 bytes), plus overhead for the outer array object and the rows inner array objects. For a int[1000][1000] array, integer data alone is 4 MB. The JVM also allocates 1001 array objects (one outer, 1000 inner). For very large matrices, memory layout and cache efficiency become important considerations.
Can you change the size of a 2D array after creation?
No. Like 1D arrays, a 2D array's dimensions are fixed at creation. However, in a jagged array, you can replace a row with a new array of a different length — arr[i] = new int[newLength]. This changes the size of that row but does not affect the outer array's row count. For fully dynamic 2D data, use ArrayList<ArrayList<Integer>>.
What is Arrays.deepEquals() and when do you use it?
Arrays.equals() compares 1D arrays element by element. For 2D arrays, it compares row references — two 2D arrays that hold equal values but are different objects return false. Arrays.deepEquals(a, b) recursively compares every element at every level — two 2D arrays with the same values in the same positions return true. Always use Arrays.deepEquals() when comparing multi-dimensional arrays for content equality.
Summary
Multi-dimensional arrays in Java are arrays of arrays. A 2D array is a grid — rows accessed by the first index, columns by the second. A jagged array lets rows have different lengths. A 3D array adds another dimension for data that naturally exists in three axes — months × products × weeks, layers × rows × columns.
The traversal pattern is always nested loops — one per dimension, using arr[i].length in the inner loop rather than a fixed column count. The most useful diagnostic tool is Arrays.deepToString() — print it before debugging and after any operation to see the full state of the array.
For interviews, be ready to traverse a 2D array and compute row sums and column sums simultaneously, explain what a jagged array is and how it differs from a regular 2D array, demonstrate the transpose operation, and explain why Arrays.toString() fails on 2D arrays.
What to Read Next
| Topic | Link |
|---|---|
| How 1D arrays work as the building block of multi-dimensional arrays | Java Arrays → |
| How ArrayList provides a dynamic alternative when the size of rows changes | Java ArrayList → |
| How the Arrays utility class provides sort, search, copy and deepToString | Java Collections Framework → |
| How nested loops drive 2D array traversal and other matrix-like operations | Java Variables → |
| How strings relate to char arrays and why 2D char arrays can represent text grids | Java String Class → |