Java OOP

Build a BankAccount class

Description: Create a class BankAccount with a private balance. Add deposit(amount) and withdraw(amount). Refuse a negative deposit and a withdraw bigger than the balance (throw an exception). Test it.

Hint:

  • Keep the field private and give a getter only.
  • Throw IllegalArgumentException and IllegalStateException.

Solution

class BankAccount {
    private double balance;

    void deposit(double amount) {
        if (amount <= 0) throw new IllegalArgumentException("Deposit must be positive");
        balance += amount;
    }

    void withdraw(double amount) {
        if (amount > balance) throw new IllegalStateException("Not enough balance");
        balance -= amount;
    }

    double getBalance() { return balance; }
}

public class Main {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount();
        acc.deposit(1000);
        acc.withdraw(250);
        System.out.println(acc.getBalance());

        try {
            acc.withdraw(5000);
        } catch (IllegalStateException e) {
            System.out.println("Error: " + e.getMessage());
        }
        try {
            acc.deposit(-5);
        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
Output

750.0
Error: Not enough balance
Error: Deposit must be positive

How it works

  • The balance is private, so the only way to change it is through the two methods which check the values.

Read Java Encapsulation.

Calculate areas with inheritance and polymorphism

Description: Make an abstract class Shape with an abstract method area(). Write Circle and Rectangle which extend it. Put a circle (radius 2) and a rectangle (3 x 4) in one array and print the total area.

Hint:

  • Use an array of type Shape[].

Solution

abstract class Shape {
    abstract double area();
}

class Circle extends Shape {
    private final double r;
    Circle(double r) { this.r = r; }
    double area() { return Math.PI * r * r; }
}

class Rectangle extends Shape {
    private final double w, h;
    Rectangle(double w, double h) { this.w = w; this.h = h; }
    double area() { return w * h; }
}

public class Main {
    public static void main(String[] args) {
        Shape[] shapes = { new Circle(2), new Rectangle(3, 4) };
        double total = 0;
        for (Shape s : shapes) {
            total += s.area();
        }
        System.out.printf("Total area: %.2f%n", total);
    }
}
Output

Total area: 24.57

How it works

  • The loop uses the type Shape. Java calls the area() of the real object (polymorphism).
  • You can add a new shape without changing the loop.

Read Polymorphism and Abstract Classes.

Sort a list of students with a Comparator

Description: You have students (name and marks). Sort them by marks, highest first. When the marks are equal, sort by name.

Hint:

  • Use Comparator.comparingInt(...).reversed() and thenComparing(...).

Solution

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

record Student(String name, int marks) { }

public class Main {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>(List.of(
                new Student("Meera", 88), new Student("Aman", 95),
                new Student("Riya", 88), new Student("Karan", 70)));

        list.sort(Comparator.comparingInt(Student::marks).reversed()
                .thenComparing(Student::name));

        list.forEach(System.out::println);
    }
}
Output

Student[name=Aman, marks=95]
Student[name=Meera, marks=88]
Student[name=Riya, marks=88]
Student[name=Karan, marks=70]

How it works

  • comparingInt compares by the marks, and reversed() makes it descending.
  • thenComparing is used only when the first comparison says the values are equal.

Read Lambda Expressions.

Create a custom exception for an invalid age

Description: Create a checked exception InvalidAgeException. Write a method register(int age) which throws it when the age is below 18, and catch it in main.

Hint:

  • Extend Exception, and use throws in the method line.

Solution

class InvalidAgeException extends Exception {
    InvalidAgeException(String message) {
        super(message);
    }
}

public class Main {
    static void register(int age) throws InvalidAgeException {
        if (age < 18) {
            throw new InvalidAgeException("Age " + age + " is below 18");
        }
        System.out.println("Registered, age " + age);
    }

    public static void main(String[] args) {
        for (int age : new int[]{25, 15}) {
            try {
                register(age);
            } catch (InvalidAgeException e) {
                System.out.println("Cannot register: " + e.getMessage());
            }
        }
    }
}
Output

Registered, age 25
Cannot register: Age 15 is below 18

How it works

  • Because the class extends Exception (not RuntimeException), it is checked: the compiler forces the caller to handle it.

Read Java Exceptions.