Before this lesson

Understand Java methods, parameters and fields, and recognize constructor calls.

What you will be able to do

Maintain object invariants through constructors and methods.

Understand the mechanism

A class describes state and behavior; an object is an instance. Each Progress has its own done counter. A static counter would instead be shared across instances.

private prevents direct field updates. The constructor validates total and complete enforces the upper bound, keeping 0<=done<=total. Encapsulation protects rules rather than mechanically adding setters.

A zero total requires a defined percentage policy; here it is zero. Convert to long before multiplying by 100 to avoid intermediate int overflow. Integer division truncates toward zero, equivalent to flooring these nonnegative values.

Runnable example

Use JDK 21. Save Main.java in a separate practice directory, compile with javac -encoding UTF-8 Main.java, then run java Main. Each lesson is independent; do not combine multiple public Main classes.


public class Main {
    static class Progress {
        private final int total;
        private int done;
        Progress(int total) {
            if (total < 0) throw new IllegalArgumentException("negative total");
            this.total = total;
        }
        void complete() { if (done < total) done++; }
        int percent() { return total == 0 ? 0 : (int) ((long) done * 100 / total); }
    }
    public static void main(String[] args) {
        Progress first = new Progress(4);
        Progress second = new Progress(4);
        first.complete();
        System.out.println(first.percent() + " " + second.percent());
        Progress empty = new Progress(0);
        empty.complete();
        System.out.println(empty.percent());
    }
}

Trace and verify

The two instances output 25 and 0, demonstrating independent state. Completing a zero-total instance leaves its percentage at zero.

Common mistakes and boundaries

This class has no synchronization and is used in a single-threaded program. final prevents field reassignment; it does not automatically make arbitrary objects deeply immutable.

Practice challenge

Call complete three times for a total of 2 and check that a negative total is rejected.

Reference solution and reasoning

The upper-bound condition blocks the third increment, leaving 100 percent. new Progress(-1) throws IllegalArgumentException, requiring corrected input.

Further reading