Loop Arrays
Most work with arrays means visiting their elements: summing, searching, filtering, transforming, comparing neighbors, or printing. Java offers several ways to loop through an array, and each suits different needs. Choosing the right one makes code shorter, clearer, and less likely to step outside the array's bounds.
The Index-Based for Loop
The classic for loop gives you each index, and through it each element:
String[] cities = {"Chennai", "Mumbai", "Delhi", "Kolkata"};
for (int i = 0; i < cities.length; i++) {
System.out.println(i + ": " + cities[i]);
}
Output:
0: Chennai
1: Mumbai
2: Delhi
3: Kolkata
The loop variable i starts at 0, the first valid index, and the condition i < cities.length stops after the last valid index, length - 1. Use this form when you need:
- the position of each element (numbering, reporting where something was found),
- to modify elements in place,
- to look at neighboring elements,
- to step through in a different order (backward, every second element),
- to walk two arrays together by index.
Modifying elements in place
double[] prices = {499, 1299, 89.5};
for (int i = 0; i < prices.length; i++) {
prices[i] = prices[i] * 1.18; // add 18% GST to every price
}
System.out.println(Arrays.toString(prices));
// [588.8199999999999, 1532.82, 105.61]
Only an index-based loop can replace elements, because it can write to prices[i]. The first value shows a binary floating-point rounding artifact: 1.18 cannot be represented exactly in a double. For display, format the value (String.format("%.2f", x)); for real money calculations, use BigDecimal.
The Enhanced for Loop (for-each)
When you only need each value, the enhanced for loop is shorter and cannot go out of bounds:
int[] marks = {78, 92, 45, 66, 88};
int total = 0;
for (int m : marks) {
total += m;
}
System.out.println("Average: " + (double) total / marks.length); // Average: 73.8
Read for (int m : marks) as "for each m in marks." The loop visits every element from first to last.
Limitation: the loop variable is a copy
Assigning to the loop variable does not change the array:
int[] nums = {1, 2, 3};
for (int n : nums) {
n = n * 10; // changes the local copy only
}
System.out.println(Arrays.toString(nums)); // [1, 2, 3]
For arrays of objects, the loop variable is a copy of the reference, so calling methods on it does affect the object:
StringBuilder[] parts = { new StringBuilder("a"), new StringBuilder("b") };
for (StringBuilder sb : parts) {
sb.append("!"); // modifies the object the array refers to
}
System.out.println(Arrays.toString(parts)); // [a!, b!]
But replacing the element (sb = new StringBuilder()) still has no effect on the array.
| Need | Index for | for-each |
|---|---|---|
| Read every value | ✓ | ✓ (simpler) |
| Know the index | ✓ | ✗ |
| Replace elements | ✓ | ✗ |
| Iterate backward or skip | ✓ | ✗ |
| Risk of off-by-one errors | Possible | None |
Looping Backward
char[] word = {'j', 'a', 'v', 'a'};
StringBuilder reversed = new StringBuilder();
for (int i = word.length - 1; i >= 0; i--) {
reversed.append(word[i]);
}
System.out.println(reversed); // avaj
Start at the last index, length - 1, and continue while i >= 0. Starting at length or stopping at i > 0 are both common off-by-one mistakes.
Backward iteration is also the safe direction when removing items from a list by index, since removing an element shifts only the elements after it.
Stepping and Ranges
int[] data = {10, 20, 30, 40, 50, 60, 70};
for (int i = 0; i < data.length; i += 2) { // every second element
System.out.print(data[i] + " "); // 10 30 50 70
}
System.out.println();
for (int i = 2; i <= 4; i++) { // a sub-range: indexes 2 to 4
System.out.print(data[i] + " "); // 30 40 50
}
Comparing Neighbors
To compare each element with the next, stop one element early so that i + 1 remains a valid index:
int[] dailySteps = {6200, 8100, 7500, 9800, 9900, 4300};
for (int i = 0; i < dailySteps.length - 1; i++) {
int change = dailySteps[i + 1] - dailySteps[i];
System.out.printf("Day %d → %d: %+d%n", i + 1, i + 2, change);
}
Output:
Day 1 → 2: +1900
Day 2 → 3: -600
Day 3 → 4: +2300
Day 4 → 5: +100
Day 5 → 6: -5600
%+d prints the sign for positive numbers too. Alternatively, start at 1 and compare a[i] with a[i - 1]; both forms keep every index valid.
Searching and Stopping Early
When looking for a single element, stop as soon as it is found:
static int indexOf(String[] items, String target) {
for (int i = 0; i < items.length; i++) {
if (items[i].equals(target)) {
return i; // leave the loop and the method immediately
}
}
return -1; // not found
}
System.out.println(indexOf(cities, "Delhi")); // 2
System.out.println(indexOf(cities, "Pune")); // -1
Use break instead of return when the loop is not inside its own method. Use continue to skip elements that should not be processed:
for (int m : marks) {
if (m < 50) continue; // ignore failing marks
System.out.println("Passed with " + m);
}
Walking Two Arrays Together
Parallel arrays (where index i in one corresponds to index i in another) require an index loop:
String[] items = {"Pen", "Notebook", "Bag"};
int[] qty = {10, 3, 1};
double[] unitPrice = {12.5, 80, 999};
double total = 0;
for (int i = 0; i < items.length; i++) {
double line = qty[i] * unitPrice[i];
total += line;
System.out.printf("%-10s %3d × %7.2f = %8.2f%n", items[i], qty[i], unitPrice[i], line);
}
System.out.printf("Total: %.2f%n", total);
Output:
Pen 10 × 12.50 = 125.00
Notebook 3 × 80.00 = 240.00
Bag 1 × 999.00 = 999.00
Total: 1364.00
All three arrays must have the same length. In larger programs, an array of records (record Item(String name, int qty, double price)) avoids keeping separate arrays in sync.
Nested Loops for 2D Arrays
int[][] seats = {
{1, 1, 0, 1},
{0, 1, 1, 1},
{1, 0, 0, 1}
};
int free = 0;
for (int row = 0; row < seats.length; row++) {
for (int col = 0; col < seats[row].length; col++) {
if (seats[row][col] == 0) {
free++;
System.out.println("Free seat: row " + (row + 1) + ", seat " + (col + 1));
}
}
}
System.out.println(free + " seats free");
for (int[] row : seats) { // for-each over rows, then over values
for (int s : row) {
System.out.print(s == 1 ? "■ " : "□ ");
}
System.out.println();
}
Output:
Free seat: row 1, seat 3
Free seat: row 2, seat 1
Free seat: row 3, seat 2
Free seat: row 3, seat 3
4 seats free
■ ■ □ ■
□ ■ ■ ■
■ □ □ ■
The outer loop goes through rows; the inner loop goes through the columns of the current row, using seats[row].length so jagged arrays also work.
while Loops over Arrays
A while loop suits cases where the index does not advance by one every time, such as the two-pointer technique:
static boolean isPalindrome(char[] s) {
int left = 0, right = s.length - 1;
while (left < right) {
if (s[left] != s[right]) return false;
left++;
right--;
}
return true;
}
System.out.println(isPalindrome("malayalam".toCharArray())); // true
Two indexes move toward each other from opposite ends, so the loop runs only half as many times as there are characters.
Streams over Arrays
The Stream API offers a declarative alternative for common operations (streams have their own section):
import java.util.Arrays;
import java.util.stream.IntStream;
int[] marks = {78, 92, 45, 66, 88};
int sum = Arrays.stream(marks).sum(); // 369
double avg = Arrays.stream(marks).average().orElse(0); // 73.8
long passed = Arrays.stream(marks).filter(m -> m >= 50).count(); // 4
int[] curved = Arrays.stream(marks).map(m -> Math.min(100, m + 5)).toArray();
IntStream.range(0, marks.length) // indexes 0..4
.filter(i -> marks[i] < 50)
.forEach(i -> System.out.println("Failed: index " + i)); // Failed: index 2
Streams express what to compute rather than how to loop. A plain loop is often clearer for simple cases and when the logic includes early exits or modifications.
Practical Example: Sales Analysis
import java.util.Arrays;
public class SalesAnalysis {
public static void main(String[] args) {
String[] months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun"};
int[] sales = {42000, 38500, 51000, 0, 47250, 56800};
int total = 0, activeMonths = 0;
for (int s : sales) { // for-each: values only
if (s == 0) continue; // skip months with no data
total += s;
activeMonths++;
}
double average = (double) total / activeMonths;
int best = 0;
for (int i = 1; i < sales.length; i++) { // index loop: track position
if (sales[i] > sales[best]) best = i;
}
System.out.printf("Total: %,d Average: %,.0f%n", total, average);
System.out.println("Best month: " + months[best]);
System.out.println("Month-over-month:");
for (int i = 1; i < sales.length; i++) { // neighbors
if (sales[i] == 0 || sales[i - 1] == 0) {
System.out.println(" " + months[i] + ": n/a");
continue;
}
double pct = 100.0 * (sales[i] - sales[i - 1]) / sales[i - 1];
System.out.printf(" %s: %+.1f%%%n", months[i], pct);
}
int[] aboveAverage = Arrays.stream(sales).filter(s -> s > average).toArray();
System.out.println("Above average: " + Arrays.toString(aboveAverage));
}
}
Output:
Total: 235,550 Average: 47,110
Best month: Jun
Month-over-month:
Feb: -8.3%
Mar: +32.5%
Apr: n/a
May: n/a
Jun: +20.2%
Above average: [51000, 47250, 56800]
The program uses each loop form for what it does best. A for-each loop totals the values, using continue to skip a month with no data. An index loop finds the best month, because the answer is a position used to look up the month name. A neighbor loop starting at index 1 computes month-over-month change, guarding against division by zero. A stream filters the values above the average in one line. Recognizing which loop shape a task needs is most of the work of processing arrays.