Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java OOP exercises: invariant-preserving reservations and independent snapshots

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

Object-oriented boundary exercises check whether every public operation preserves the object’s stated invariant under rejected as well as accepted inputs.

Java 8+. This is a complete program using JDK classes.

Implement before reading the solution

Create a stock reservation object with non-negative available and reserved counts. reserve rejects non-positive quantities and returns false when stock is insufficient. A rejected request must not change either field. Expose an independent two-number snapshot rather than the object’s internal storage.

Test a successful reservation, an over-capacity request, zero input and mutation of a returned snapshot. State whether invalid input throws or returns a rejected result; this solution throws for a malformed quantity and returns false for a valid request that exceeds available stock.

The two rejection reasons are intentionally different. A UI can ask the customer to choose a smaller amount after insufficient stock, but zero is not a valid reservation quantity. A caller should not need to inspect a partially updated object to determine which branch occurred.

Working program

Java
public class ReservationBoundaryExercises {
    static final class Stock {
        private int available,reserved;
        Stock(int available){if(available<0)throw new IllegalArgumentException("Negative stock");this.available=available;}
        boolean reserve(int quantity){
            if(quantity<=0)throw new IllegalArgumentException("Positive quantity required");
            if(quantity>available)return false;
            available-=quantity;reserved+=quantity;return true;
        }
        int[] snapshot(){return new int[]{available,reserved};}
    }
    static void require(boolean condition){if(!condition)throw new AssertionError("Boundary failed");}
    public static void main(String[] args){
        Stock stock=new Stock(10);require(stock.reserve(3));
        require(!stock.reserve(20));require(stock.snapshot()[0]==7&&stock.snapshot()[1]==3);
        try{stock.reserve(0);throw new AssertionError("Zero accepted");}catch(IllegalArgumentException expected){ }
        int[] detached=stock.snapshot();detached[0]=99;require(stock.snapshot()[0]==7);
        System.out.println("4 reservation checks passed");
    }
}

Output

Output
4 reservation checks passed

Costs and boundaries

Each operation touches fixed-sized state and uses O(1) work. Each snapshot allocates a two-element array. This model is single-threaded; sharing it between workers requires protecting the full available/reserved transition, not just marking each field volatile.

Common Mistakes

  • Reject before mutating.
  • A snapshot must not expose owned mutable storage.
  • Separate malformed requests from valid requests that cannot be fulfilled.

Read next

Public invariants, Coordinated updates.

java
oop-exercises
Storage details