November 13, 2026•6 min read

Java Loops: the Last Price That Never Reached the Sum

Four prices add up to 47000, and the cart program prints 36500. The bound is prices.length - 1, so the last item is never read while the average is still divided by four.

Read in Indonesian

You run a small program that totals a cart of four items. It prints three lines, and the second one says the total is 36,500. The third gives an average price. The run exits normally, and not one of the three lines looks broken. Only the arithmetic disagrees with the receipt.

Key takeaways

  • i < prices.length - 1 stops the loop one index early, so the last price never enters the sum.
  • The average still divides by prices.length, so the total and the average are both wrong while the count line stays right.
  • The mirror bound i <= prices.length throws ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4.
  • for (int price : prices) walks the array with no index, so there is no bound to write one short, and it gives up the position.
  • while tests before the body and prints nothing on an empty array; do-while tests after and runs the body once.
  • A checker whose expectations are fixed fails on correct code when the input changes, so it tests the input as much as the code.

The loop that stops at the third item

The file holds an int array of four prices, a counter, a sum, and an average.

JAVA
// Total.java
public class Total {
    public static void main(String[] args) {
        int[] prices = {12000, 15000, 9500, 10500};
        System.out.println("items: " + prices.length);
        int total = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            total += prices[i];
        }
        System.out.println("total: " + total);
        System.out.println("average: " + total / prices.length);
    }
}

Compile and run it with javac Total.java && java Total. The exit status is 0, with no warning and no error.

Output
$ javac Total.java && java Total
items: 4
total: 36500
average: 9125

That is three lines, and all of them are plausible. The count says 4, the total is a believable number, and so is the average. But the four prices add to 47000, so the total is 10,500 short.

Why the last item never enters the loop

Look at the bound: prices.length - 1. The array holds four prices, so that is 3, and the condition i < 3 holds for i equal to 0, 1 and 2. Index 3 is never read. The last price, 10500, never reaches the sum.

The damage has a second half. The average still divides by prices.length, which is 4. So two lines are wrong, not one. The total is short by 10500, and that short total is then divided by four items when only three were added. The right average is 47000 / 4, which is 11750.

The mirror mistake keeps the same array and the same loop body, and changes only the bound. Write i <= prices.length instead. This version does not skip an item. It reads past the end, and the program stops with java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4. The trace points at Total.main(Total.java:8), and the process exits with status 1.

One of these mistakes is silent and the other is loud. The silent one ships.

A check you can run

You can catch the quiet version with a second program. This checker reads the three lines the program prints and compares them against the values the four prices should produce.

JAVA
// CheckTotal.java
import java.util.List;
import java.util.Scanner;

public class CheckTotal {
    public static void main(String[] args) {
        List<String> expected = List.of("items: 4", "total: 47000", "average: 11750");
        Scanner in = new Scanner(System.in);
        int passed = 0;
        for (int i = 0; i < expected.size(); i++) {
            String got = in.hasNextLine() ? in.nextLine() : "<nothing>";
            if (got.equals(expected.get(i))) {
                passed++;
                System.out.println("PASS  line " + (i + 1) + ": " + got);
            } else {
                System.out.println("FAIL  line " + (i + 1) + ": expected " + expected.get(i) + ", got " + got);
            }
        }
        if (in.hasNextLine()) {
            System.out.println("FAIL  extra line: " + in.nextLine());
        }
        System.out.println();
        System.out.println(passed + " of " + expected.size() + " checks passed");
        if (passed != expected.size()) {
            System.exit(1);
        }
    }
}

Pipe the program into it with javac CheckTotal.java && java Total | java CheckTotal.

Output
$ javac CheckTotal.java && java Total | java CheckTotal
PASS  line 1: items: 4
FAIL  line 2: expected total: 47000, got total: 36500
FAIL  line 3: expected average: 11750, got average: 9125

1 of 3 checks passed

The line items: 4 passes. The total and the average do not, so the checker prints 1 of 3 checks passed and exits non-zero. The program alone said nothing, and the checker caught it at once.

Stop counting

The fix is to stop counting. Swap the counted loop for a for-each loop and change nothing else.

JAVA
// Total.java
public class Total {
    public static void main(String[] args) {
        int[] prices = {12000, 15000, 9500, 10500};
        System.out.println("items: " + prices.length);
        int total = 0;
        for (int price : prices) {
            total += price;
        }
        System.out.println("total: " + total);
        System.out.println("average: " + total / prices.length);
    }
}
Output
$ javac Total.java && java Total
items: 4
total: 47000
average: 11750
Output
$ java Total | java CheckTotal
PASS  line 1: items: 4
PASS  line 2: total: 47000
PASS  line 3: average: 11750

3 of 3 checks passed

The for-each loop hands you the value instead of the position. Against this file the checker prints 3 of 3 checks passed and exits 0. The loop visits every element exactly once, in order. There is no bound to write down, so there is nothing to get one short.

The trade is honest: you lose the index. If you need to know which position you are on, the counted for stays the right tool.

The other two loops

A while loop earns its place when you repeat work as long as a condition holds and there is no counter to advance. You state the condition, and the loop runs until it turns false.

A do-while loop tests its condition after the body. That means the body always runs once before the first test.

JAVA
// Rows.java
public class Rows {
    public static void main(String[] args) {
        int[] empty = {};
        int i = 0;
        while (i < empty.length) {
            System.out.println("while row " + i);
            i++;
        }
        int j = 0;
        do {
            System.out.println("do-while row " + j);
            j++;
        } while (j < empty.length);
    }
}
Output
$ javac Rows.java && java Rows
do-while row 0

The while loop never runs on the empty array, because its condition is false before the body starts, and the do-while loop runs once. Inside any of these loops, break leaves the loop early and continue jumps to the next pass. As a rule of thumb, pick the loop whose stopping condition you can state without arithmetic.

Before the next article

Remove one price from the array, so it holds three values such as {12000, 15000, 10500}. Run the fixed program. It prints items: 3, total: 37500 and average: 12500, and all three lines are correct.

Now run the unchanged checker. It reports 0 of 3 checks passed, even though the code is now correct, because it expects four items. The checker's expectations are fixed at four items, so it tests the input as much as it tests the code.

Which line of your own last loop would you have to change if the array grew by one tomorrow?

Get better at shipping code.

Join the other developers getting tech updates, tips, and relaxed tutorials in their inbox every week.

Stay in the loop

Tech updates, coding tips, and relaxed insights straight to your inbox every week.

No spam. Unsubscribe anytime.

Read next

See all
Struktur DataWhat a Linked List Actually Is

A linked list is a linear chain of nodes, each holding data and a pointer to the next node. Here is what that chain looks like, what it costs next to an array, and the same minimal implementation in Java, Python, and JavaScript.

For developers who learn by struggling

© 2026 Inva.dev.