Home › Learn › Java › Exceptions, and the project

Exceptions

Lesson 36 of 40. Refuse bad input loudly, and recover from failures.

throw new IllegalArgumentException("amount must be positive"); stops the current method and hands an exception up to whoever called it, and so on up, until a try block with a matching catch handles it or the program ends. Throwing is the right response to input a method cannot do anything sensible with; a made-up return value hides the problem until it surfaces somewhere confusing. IllegalArgumentException (bad input) and IllegalStateException (a valid request at the wrong time) cover most cases.

try { ... } catch (IllegalStateException e) { ... } catches that type and its subtypes; several catch blocks handle several types, most specific first; finally { ... } runs either way and is for cleanup. e.getMessage() is the text given to the constructor. Catch only what you can handle, and let the rest propagate.

One thing to know about this browser runtime: a null reference, an array index out of range, and an integer division by zero stop the program instead of throwing a catchable exception, so check for those cases before they happen (which is good practice anyway). Everything thrown with throw behaves exactly as in Java.

static double sqrt(double x) {
    if (x < 0) {
        throw new IllegalArgumentException("negative input");
    }
    return Math.sqrt(x);
}

try {
    sqrt(-1);
} catch (IllegalArgumentException e) {
    System.out.println("caught: " + e.getMessage());
}

Your task

Write static int withdraw(int balance, int amount) that throws an IllegalArgumentException with the message amount must be positive when the amount is zero or less, throws an IllegalStateException with the message insufficient funds when the amount exceeds the balance, and otherwise returns the new balance. Then write static String tryWithdraw(int balance, int amount) returning ok <new balance> on success or error: <message> when either exception is thrown.

Hint 1

if (amount <= 0) throw new IllegalArgumentException("amount must be positive"); if (amount > balance) throw new IllegalStateException("insufficient funds");

Hint 2

tryWithdraw: try { return "ok " + withdraw(balance, amount); } catch (IllegalArgumentException | IllegalStateException e) { return "error: " + e.getMessage(); } (the | catches either type; RuntimeException would catch both too).

Show the solution
public class Main {
    static int withdraw(int balance, int amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("amount must be positive");
        }
        if (amount > balance) {
            throw new IllegalStateException("insufficient funds");
        }
        return balance - amount;
    }

    static String tryWithdraw(int balance, int amount) {
        try {
            return "ok " + withdraw(balance, amount);
        } catch (IllegalArgumentException | IllegalStateException e) {
            return "error: " + e.getMessage();
        }
    }

    public static void main(String[] args) {
        System.out.println(tryWithdraw(100, 30) + " / " + tryWithdraw(10, 50));
    }
}

    Compiles with OpenJDK javac and TeaVM, both compiled to WebAssembly (7 MB download the first time, then cached), and runs in this tab; nothing is sent anywhere.