Java Tutorial
🔍

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

Java
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.

Java
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.

Java
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.

Java
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

AspectRegular 2D ArrayJagged Array3D Array
Declarationint[][] a = new int[3][4]int[][] a = new int[3][]int[][][] a = new int[2][3][4]
Column countSame for every rowCan differ per rowSame per slice
Memory layoutRectangular gridIrregular — each row separateCube of values
Access syntaxa[row][col]a[row][col]a[layer][row][col]
Row length checka[0].length works for allMust use a[row].lengtha[0][0].length
When to useTables, matrices, gridsVariable-length rows, triangles3D spatial data, time series grids
Memory efficiencyFixed — may waste slotsEfficient — only allocates what is neededHigher overhead
Common use caseExam scores, seating chartPascal's Triangle, timetableRGB 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.

Java
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.

Java
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.

Java
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()

Java
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

Java
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 it

Mistake 3 — Wrong Loop Condition for Inner Loop

Java
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

Java
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 array

Interview 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

TopicLink
How 1D arrays work as the building block of multi-dimensional arraysJava Arrays →
How ArrayList provides a dynamic alternative when the size of rows changesJava ArrayList →
How the Arrays utility class provides sort, search, copy and deepToStringJava Collections Framework →
How nested loops drive 2D array traversal and other matrix-like operationsJava Variables →
How strings relate to char arrays and why 2D char arrays can represent text gridsJava String Class →
Java Multi-dimensional Arrays | DevStackFlow