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 is moduleCurrents.length - 1; the last valid column index is moduleCurrents[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.
  • .length gives the row count; .length on 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)