Real World Example

A Swiggy-style Cart Item

Food delivery apps model every item in your cart as an object. Constructors set safe defaults, a static counter generates line ids, and toString makes logs readable.

Example

public class Main {
    public static void main(String[] args) {
        CartItem a = new CartItem("Masala Dosa", 120);
        CartItem b = new CartItem("Filter Coffee", 40, 2);
        a.increase().increase();
        System.out.println(a);
        System.out.println(b);
        System.out.println("Cart total: Rs " + (a.total() + b.total()));
        System.out.println("Lines created: " + CartItem.nextId);
    }
}

class CartItem {
    static int nextId = 0;
    final int lineId;
    final String name;
    final int price;
    int qty;

    CartItem(String name, int price) {
        this(name, price, 1);
    }

    CartItem(String name, int price, int qty) {
        if (price <= 0) throw new IllegalArgumentException("price must be positive");
        this.lineId = ++nextId;
        this.name = name;
        this.price = price;
        this.qty = qty;
    }

    CartItem increase() {
        qty++;
        return this;
    }

    int total() {
        return price * qty;
    }

    @Override
    public String toString() {
        return "#" + lineId + " " + name + " x" + qty + " = Rs " + total();
    }
}

Output

#1 Masala Dosa x3 = Rs 360
#2 Filter Coffee x2 = Rs 80
Cart total: Rs 440
Lines created: 2

Key Takeaways

  • Use constructor chaining (this(...)) so validation lives in one place.
  • Use final fields for values that never change after creation (id, name, price).
  • Use static only for data that is truly shared (id generators, constants).
  • Always override toString on domain classes: it makes logs and debugging much easier.