An array on its own is just storage. It becomes useful the moment a loop walks it, because then one body of code processes every element no matter how many there are. Walking every element in order is called traversal, and the classic form counts an index from 0 up to but not including the length. Learn for (int i = 0; i < arr.length; i++) as one fixed phrase and type it as a unit: i = 0 starts at the first element, i < arr.length stops one past the last valid index, and i++ moves on by one slot.
int[] marks = {78, 92, 65, 88, 71};
for (int i = 0; i < marks.length; i++) {
System.out.println("Mark " + i + " is " + marks[i]);
}When you only need the values and never the positions, Java offers a shorter form. Read for (int mark : marks) as "for each mark in marks". There is no counter to initialize, no condition to get wrong and no index to go out of bounds, so it removes a whole family of bugs at once — which is why you should reach for it by default. It cannot be used in two situations, though. The first is when you need the index itself, to report a position, to step backwards, or to visit only part of the array. The second is when you need to modify the elements: the loop variable receives a copy of each element, so assigning to it changes the copy and leaves the array untouched, with no warning from the compiler at all. To write into an array you need the index, and therefore the standard for loop.
int[] values = {1, 2, 3};
int total = 0;
for (int v : values) {
total += v; // reading is exactly what for-each is for
}
System.out.println(total); // 6
for (int v : values) {
v = v * 10; // changes only the copy
}
System.out.println(values[0]); // still 1 - nothing happened
for (int i = 0; i < values.length; i++) {
values[i] = values[i] * 10; // writes back into the array
}
System.out.println(values[0]); // now 10The accumulator pattern is the same as with any loop: declare the total before the loop, add inside it, use it after. The one trap is the average, because dividing two ints in Java throws away the fractional part. 394 / 5 gives 78, not 78.8. Casting one side to double fixes it, and the cast must happen before the division, not after — (double) total / n is right, while (double) (total / n) has already lost the decimals by the time the cast runs.
public class MarkStats {
public static void main(String[] args) {
int[] marks = {78, 92, 65, 88, 71};
int total = 0;
for (int mark : marks) {
total += mark;
}
double average = (double) total / marks.length;
System.out.println("Total: " + total); // 394
System.out.println("Average: " + average); // 78.8
}
}int max = arr[0]; and then loop from index 1. Starting at 0 works only when every element is positive — feed it a week of winter temperatures and it will confidently report 0, a value that is not even in the array. Starting from the first element guarantees the running maximum is always a real member of the data. The same rule applies to the minimum.int[] temps = {-5, -12, -3, -8};
int max = temps[0];
int min = temps[0];
for (int i = 1; i < temps.length; i++) {
if (temps[i] > max) {
max = temps[i];
}
if (temps[i] < min) {
min = temps[i];
}
}
System.out.println("High: " + max); // -3
System.out.println("Low: " + min); // -12Counting asks "how many", so it visits every element and increments a counter inside an if. Searching asks "where", so it can stop the instant it finds what it wants. The convention for a search that finds nothing is to return −1, because −1 is never a valid index and so can never be mistaken for a real answer. One warning about where that line goes: return -1; must be after the loop, not in an else inside it. Put it inside and the method reports failure after checking only the first element — the search has failed only once the whole loop has finished without returning.
public class Search {
// How many marks are at least the cutoff?
public static int countAtLeast(int[] arr, int cutoff) {
int count = 0;
for (int value : arr) {
if (value >= cutoff) {
count++;
}
}
return count;
}
// Where is the target? Returns the index, or -1 if it is absent.
public static int indexOf(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i; // found it - stop immediately
}
}
return -1; // only reached if the loop never matched
}
public static void main(String[] args) {
int[] marks = {78, 92, 65, 88, 71};
System.out.println(countAtLeast(marks, 80)); // 2
System.out.println(indexOf(marks, 65)); // 2
System.out.println(indexOf(marks, 50)); // -1
}
}Swapping two elements needs a third variable. Writing a[i] = a[j]; first destroys the old value of a[i] before anything has saved it, so both slots end up holding the same thing. Park one value in a temporary variable, and the swap is three safe lines: save, copy over, restore. Reversing an array is that same swap applied from both ends inwards, which is why the loop only runs to the halfway point — going all the way would swap every pair twice and put the array back exactly as it started.
int[] a = {1, 2, 3, 4, 5};
for (int i = 0; i < a.length / 2; i++) {
int temp = a[i]; // 1. save
a[i] = a[a.length - 1 - i]; // 2. copy over
a[a.length - 1 - i] = temp; // 3. restore
}
// i = 0 swaps a[0] and a[4] -> 5 2 3 4 1
// i = 1 swaps a[1] and a[3] -> 5 4 3 2 1
// loop stops: 5 / 2 is 2, so i never reaches 2 and the middle stays putReal data has more than one field per thing: a student has a name and a mark, a product has a code and a price. Before you meet objects, the usual answer is parallel arrays — two or more arrays of the same length where index i in each refers to the same real-world item. Write String[] names = {"Aisha", "Ben", "Chloe"}; beside int[] marks = {88, 72, 95}; and one loop over the shared index prints names[i] + ": " + marks[i] for each person. The arrays are joined only by that shared index, and that is exactly what makes them fragile.