Arrays
Hook
Your robot’s arm encoder reports a position reading every 20ms. You want to smooth out sensor noise by averaging the last five readings. So you create five variables:
double reading1 = 0;
double reading2 = 0;
double reading3 = 0;
double reading4 = 0;
double reading5 = 0;
Now you want the average. Then you realize you need to shift readings when a new one arrives — reading5 = reading4, reading4 = reading3, and so on. Five lines of copy/paste just to shift a window. What if you needed 20 readings?
An array stores a sequence of values under a single name. You access each one by its position. The shift becomes a loop.
Core concept
An array is an ordered, fixed-size collection of values of the same type. Elements are accessed by their index — a zero-based integer position.
Declaring and initializing arrays
There are two common ways to create an array in Java.
Fixed size, filled with zeros (or default values):
double[] readings = new double[5]; // [0.0, 0.0, 0.0, 0.0, 0.0]
int[] counts = new int[3]; // [0, 0, 0]
boolean[] flags = new boolean[4]; // [false, false, false, false]
Literal initialization — when you know the values upfront:
double[] setpoints = { 0.0, 30.0, 60.0, 90.0, 120.0 };
String[] modes = { "teleop", "auto", "test" };
The array’s size is fixed at creation. You cannot add or remove elements later.
Index access
Elements are numbered starting from 0. An array of size 5 has indices 0, 1, 2, 3, 4.
double[] readings = new double[5];
// Writing to elements:
readings[0] = 47.3;
readings[1] = 48.1;
readings[2] = 46.9;
// Reading elements:
double first = readings[0]; // 47.3
double third = readings[2]; // 46.9
// The length property:
int size = readings.length; // 5
readings.length is a property, not a method — no parentheses. This trips up beginners who expect readings.length() by analogy with String.length(). Arrays use a field; String uses a method.
Visualizing the array:
Index: 0 1 2 3 4
┌──────┬──────┬──────┬──────┬──────┐
│ 47.3 │ 48.1 │ 46.9 │ 0.0 │ 0.0 │
└──────┴──────┴──────┴──────┴──────┘
Iterating with a for loop
A standard for loop walks every element:
double[] setpoints = { 0.0, 30.0, 60.0, 90.0, 120.0 };
for (int i = 0; i < setpoints.length; i++) {
System.out.println("Setpoint " + i + ": " + setpoints[i]);
}
Output:
Setpoint 0: 0.0
Setpoint 1: 30.0
Setpoint 2: 60.0
Setpoint 3: 90.0
Setpoint 4: 120.0
The condition is i < setpoints.length, not i <= setpoints.length. If you use <=, the loop tries to access setpoints[5] — which doesn’t exist.
The enhanced for-each loop
When you only need to read values (not track the index or modify elements), the for-each loop is cleaner:
double total = 0.0;
for (double reading : readings) {
total += reading;
}
double average = total / readings.length;
Read for (double reading : readings) as “for each double named reading in readings.”
The trade-off: you lose access to the index. If you need to know which element you’re on, use the regular for loop.
FRC context: encoder history buffer
Here’s the rolling-average encoder smoother from the hook, now properly implemented:
private double[] history = new double[5];
private int nextSlot = 0;
public void updateHistory(double newReading) {
history[nextSlot] = newReading;
nextSlot = (nextSlot + 1) % history.length; // wrap around: 0,1,2,3,4,0,1,...
}
public double smoothedPosition() {
double total = 0.0;
for (double val : history) {
total += val;
}
return total / history.length;
}
Each call to updateHistory writes into the oldest slot. The modulo (%) operator wraps the index back to 0 after it reaches the end. This pattern — a circular buffer — comes up often in sensor processing.
FRC context: angle setpoints
Arrays also store lookup tables. An arm might have named positions mapped to degree values:
// Index matches a button number: button 0 → stow, button 1 → low, etc.
double[] armSetpoints = { 5.0, 30.0, 75.0, 110.0 };
int button = controller.getPOV() / 90; // D-pad: 0,90,180,270 → 0,1,2,3
double targetAngle = armSetpoints[button];
arm.setTargetDegrees(targetAngle);
Without an array, this would be four separate if/else if blocks.
Tracing an array loop
Watch a sum-of-array loop execute step by step:
i=0; check i < 3// true, enter looptotal += arr[0]// 10.0 + 0.0i++// advancecheck i < 3// truetotal += arr[1]// 10.0 + 20.0i++// advancecheck i < 3// truetotal += arr[2]// 30.0 + 30.0i++// advancecheck i < 3// false — exitStep through to see values update.
Common mistakes
Off-by-one: <= instead of <
// WRONG — ArrayIndexOutOfBoundsException when i == readings.length
for (int i = 0; i <= readings.length; i++) {
System.out.println(readings[i]);
}
// CORRECT
for (int i = 0; i < readings.length; i++) {
System.out.println(readings[i]);
}
ArrayIndexOutOfBoundsException is the most common array error. It means you tried to access an index that doesn’t exist — either negative or >= length. The exception message tells you the bad index: Index 5 out of bounds for length 5.
Hardcoding the length instead of using .length
// FRAGILE — if you change the array size, you must update this number too
for (int i = 0; i < 5; i++) { ... }
// ROBUST — always correct regardless of array size
for (int i = 0; i < readings.length; i++) { ... }
Dividing by zero when the array is empty
If you compute total / array.length and the array has length 0, you get NaN (not a number) or an exception. Guard against it:
double average(double[] values) {
if (values.length == 0) return 0.0;
double total = 0.0;
for (double v : values) total += v;
return total / values.length;
}
Knowledge check
An array is declared as: int[] data = new int[4]; What is data[4]?
You want to loop over all elements of double[] values using a for loop. Which condition is correct?
Key takeaways
- Arrays are fixed-size, zero-indexed collections of a single type.
- The last valid index is always
array.length - 1. Accessingarray[array.length]throwsArrayIndexOutOfBoundsException. - Use a regular
forloop when you need the index; use a for-each loop when you only need the values. - Always use
array.lengthin loop conditions — never hardcode the size.
Common confusions
“I assigned a new value to the for-each variable but the array didn’t change.” The for-each variable is a copy of the element for primitives (int, double, etc.). Modifying it doesn’t modify the array. Use a regular for loop with index assignment: arr[i] = newValue.
“I initialized double[] values = new double[5] but I get all zeros.” That’s correct — Java initializes numeric arrays to zero, boolean arrays to false, and object arrays to null. If you want specific values, assign them or use literal initialization { 1.0, 2.0, ... }.
Challenge
Compute the average of an array of motor speed readings. Return the average as a double. If the array is empty, return 0.0.
Stuck? Show hint
Sum all elements with a for-each loop, then divide by values.length. Check for length == 0 before dividing.
What’s next
In Lesson 8, we’ll look at classes and objects — how to bundle related data and behavior together into a reusable type, instead of managing parallel arrays of motor speeds, encoder positions, and sensor flags.