2D Array Creation and Access
Why 2D
Some data is naturally rows-and-columns, not just a flat list. Swerve drive telemetry is a good example: 4 modules (front-left, front-right, back-left, back-right), each logging several current-draw samples over time. That's a 2D array — one row per module, one column per sample.
// datatype[][] variableName = new datatype[numberRows][numberCols];
double[][] moduleCurrents = new double[4][5]; // 4 modules, 5 samples each
A 2D array variable works like any other reference type: declared as a field with no new (double[][] moduleCurrents;), it defaults to null. Declared as a local variable, Java won't even let you read it before it's assigned — that's a compile error ("variable moduleCurrents might not have been initialized"), not a null. Once created with new, every element starts at that type's default (0.0 here); how Java actually stores the rows is covered below.
Initializer Lists
An initializer list for a 2D array is a list of 1D initializer lists, one per row — size is inferred:
double[][] moduleCurrents =
{
{12.1, 11.8, 40.2, 12.4, 11.9}, // front-left
{12.0, 11.9, 12.1, 11.7, 12.2}, // front-right
{11.9, 12.3, 12.0, 11.8, 12.1}, // back-left
{12.2, 12.0, 11.9, 12.4, 11.9}, // back-right
};
Accessing Elements: arr[row][col]
The first index is the row, the second is the column:
double spike = moduleCurrents[0][2]; // front-left module, 3rd sample -> 40.2
moduleCurrents[0][2] = 0.0; // overwrite a bad reading
Printing a 2D array directly (System.out.println(moduleCurrents)) just prints its object reference, not its contents — printing every value takes nested loops (Lesson 10.2).
Row and Column Counts
The number of rows is .length; the number of columns is the length of any one row (AP CSA — and this curriculum — assumes every row has the same length, i.e. the array is rectangular, not "ragged"):
moduleCurrents.length // 4 (number of modules / rows)
moduleCurrents[0].length // 5 (samples per module / columns)
Valid row indices: 0 to length - 1. Valid column indices: 0 to arr[0].length - 1. An out-of-range index in either dimension throws ArrayIndexOutOfBoundsException, same as a 1D array.
Java Stores It as an Array of Arrays
Internally, moduleCurrents is one 4-element outer array, where each element is a reference to its own separate 5-element inner array — not one giant contiguous block. That's why moduleCurrents[0] alone is a valid expression: it's a real, complete double[] (front-left's row), which is what makes moduleCurrents[0].length work.
double[] frontLeftRow = moduleCurrents[0]; // a single row IS a real 1D array on its own
Common Pitfalls
- Swapping row and column.
moduleCurrents[2][0]is back-left's first sample, not front-left's third — the first index is always the row. - Assuming
new double[4][5]gives usable data. It gives 20 zeros, not real readings — same default-value rule as 1D arrays. - Off-by-one against
.length. The last valid row index ismoduleCurrents.length - 1; the last valid column index ismoduleCurrents[0].length - 1.
Key Takeaways
- A 2D array is declared/created as
datatype[][] name = new datatype[rows][cols];, or filled in one step with a nested initializer list (one inner list per row). arr[row][col]reads or writes one element; the first index is always the row, the second the column..lengthgives the row count;.lengthon any one row (e.g.arr[0].length) gives the column count.- Java implements a 2D array as an array of arrays — each row is itself a real, independent 1D array.
Derived from csawesome-2026: unit-4-data-collections/4.11-2d-array-creation-and-access.md (CSA 4.11)