Board Formulas
β˜• JavaπŸ“… Day 18

Exception Handling in Java

Stop programs from crashing on bad input: try, catch and finally, checked vs unchecked exceptions, throw, throws and your own exception classes.

🎯

Learning objectives

  • β†’Explain what an exception is and what happens when nobody handles it
  • β†’Handle exceptions with try, catch and finally
  • β†’Tell checked exceptions apart from unchecked ones
  • β†’Use throw and throws, and write a custom exception class

πŸ’‘ Key points

  • An exception is a problem that happens while the program runs, such as dividing by zero. If nobody catches it, the program stops and prints a stack trace.
  • Put risky code inside try. A catch (Type e) block handles a matching exception, and the program then carries on after the try-catch.
  • finally runs whether or not an exception happened. Use it for clean-up such as closing a file.
  • Catch blocks are checked from top to bottom, so put specific exceptions (ArithmeticException) before general ones (Exception).
  • Checked exceptions (IOException, FileNotFoundException) must be caught or declared with throws, and the compiler enforces this. Unchecked exceptions (subclasses of RuntimeException) do not have to be.
  • throw raises an exception right now. throws, in a method header, warns callers that the method may pass one on to them.
  • A custom exception is a class that extends Exception (checked) or RuntimeException (unchecked).

πŸ’» Code examples(6)

#1An unhandled exception
java
public class Crash {
    public static void main(String[] args) {
        int total = 500;
        int students = 0;
        System.out.println("Calculating average...");
        int avg = total / students;
        System.out.println("Average: " + avg);
    }
}
Output
Calculating average...
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Crash.main(Crash.java:6)
Dividing an int by zero throws an ArithmeticException. Nothing catches it, so Java prints the exception's name, its message and the line number (6), and the last println never runs.
#2try and catch
java
public class SafeDivide {
    public static void main(String[] args) {
        int total = 500;
        int students = 0;
        try {
            int avg = total / students;
            System.out.println("Average: " + avg);
        } catch (ArithmeticException e) {
            System.out.println("Error: " + e.getMessage());
        }
        System.out.println("Program continues");
    }
}
Output
Error: / by zero
Program continues
When the division fails, Java skips the rest of the try block and jumps to the matching catch. e.getMessage() gives a short description. After the catch, the program runs normally.
#3Several catch blocks and finally
java
public class ParseMarks {
    public static void main(String[] args) {
        String[] inputs = {"85", "abc", "92"};
        int[] marks = new int[2];

        for (int i = 0; i < inputs.length; i++) {
            try {
                marks[i] = Integer.parseInt(inputs[i]);
                System.out.println("Saved " + marks[i]);
            } catch (NumberFormatException e) {
                System.out.println("Not a number: "
                    + inputs[i]);
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("No space for "
                    + inputs[i]);
            } finally {
                System.out.println("-- done with " + i);
            }
        }
    }
}
Output
Saved 85
-- done with 0
Not a number: abc
-- done with 1
No space for 92
-- done with 2
"abc" cannot be parsed, and the array has no index 2, so each problem goes to the catch that matches its type. finally runs after every attempt, success or failure.
#4A checked exception: catch it or declare it
java
import java.io.FileReader;
import java.io.IOException;

public class ReadFile {
    public static void main(String[] args) {
        try {
            FileReader fr = new FileReader("marks.txt");
            System.out.println("File opened");
            fr.close();
        } catch (IOException e) {
            System.out.println("Could not open marks.txt");
        }
    }
}
Output
Could not open marks.txt
new FileReader(...) can throw FileNotFoundException, a kind of IOException. These are checked: remove the try-catch and javac refuses to compile. Here there is no marks.txt, so the catch runs.
#5throw: raise an exception yourself
java
public class Ticket {
    static void book(int age) {
        if (age < 18) {
            throw new IllegalArgumentException(
                "Age " + age + " is below 18");
        }
        System.out.println("Booked for age " + age);
    }

    public static void main(String[] args) {
        try {
            book(21);
            book(15);
            book(30);
        } catch (IllegalArgumentException e) {
            System.out.println("Refused: "
                + e.getMessage());
        }
    }
}
Output
Booked for age 21
Refused: Age 15 is below 18
throw new ... creates an exception object and raises it immediately. book(15) throws, so control jumps to the catch, and book(30) never runs.
#6A custom checked exception with throws
java
class LowBalanceException extends Exception {
    LowBalanceException(String msg) {
        super(msg);
    }
}

class Wallet {
    private double balance = 1000;

    void pay(double amt) throws LowBalanceException {
        if (amt > balance) {
            throw new LowBalanceException("Need Rs."
                + amt + ", have Rs." + balance);
        }
        balance -= amt;
        System.out.println("Paid Rs." + amt
            + ", left Rs." + balance);
    }
}

public class WalletDemo {
    public static void main(String[] args) {
        Wallet w = new Wallet();
        try {
            w.pay(400);
            w.pay(800);
        } catch (LowBalanceException e) {
            System.out.println("Failed: "
                + e.getMessage());
        }
    }
}
Output
Paid Rs.400.0, left Rs.600.0
Failed: Need Rs.800.0, have Rs.600.0
LowBalanceException extends Exception, so it is checked: pay() must declare throws LowBalanceException, and every caller must handle it. super(msg) stores the message that getMessage() returns.

🎯 Practice

Q1. What does finally do, and when does it run?+

It holds code that runs after the try (and any catch), whether or not an exception happened, for example closing a file. It is skipped only if the JVM itself stops, such as with System.exit().

Q2. Is NumberFormatException checked or unchecked? How can you tell?+

Unchecked. It extends IllegalArgumentException, which extends RuntimeException, so the compiler does not force you to catch it.

Q3. What is the difference between throw and throws?+

throw is a statement that raises one exception object: throw new ArithmeticException("..."); throws goes in a method header and lists the exceptions the method may pass to its caller: void read() throws IOException

Q4. Why is this a compile error? catch (Exception e) { } catch (ArithmeticException e) { }+

Exception already catches every ArithmeticException, so the second block could never run. javac reports 'exception ArithmeticException has already been caught'. Put the specific catch first.

Q5. Write a custom unchecked exception called InvalidMarksException.+

class InvalidMarksException extends RuntimeException { InvalidMarksException(String msg) { super(msg); } } // use: throw new InvalidMarksException("Marks must be 0-100");

πŸ“ Notes

The exception family tree

  • Throwable is the root of everything that can be thrown.
    • Error covers serious problems inside the JVM, such as StackOverflowError and OutOfMemoryError. Don't catch these.
    • Exception covers problems a program can recover from. It and its subclasses, such as IOException, are checked, except for one branch:
      • RuntimeException and its subclasses are unchecked: ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, NumberFormatException.

Unchecked exceptions usually mean a bug you can fix with a check, such as if (students != 0). Checked exceptions are problems outside your control, such as a missing file, so Java makes you plan for them. Forget one and you see unreported exception FileNotFoundException; must be caught or declared to be thrown.

try-with-resources (Java 7+)

Anything that must be closed, such as a file or a Scanner, can be opened in the brackets after try. Java closes it for you, even if an exception happens:

try (Scanner sc = new Scanner(System.in)) {
    int n = sc.nextInt();
    System.out.println("Read " + n);
}   // sc.close() happens automatically

Common mistakes

  • An empty catch block. catch (Exception e) { } hides the problem completely. At least print e.getMessage().
  • Catching Exception everywhere. Catch the specific type you expect, so real bugs still show up.
  • Using exceptions instead of a simple check. Test if (index < arr.length) rather than waiting for ArrayIndexOutOfBoundsException.
  • Putting the general catch first. It makes the later, specific catches unreachable, which is a compile error.

Next: Day 19, Recursion. You will write methods that call themselves, and learn why every one needs a base case.