Chapter 18 Intermediate 49 Questions

Practice Questions — Exception Handling in Java

← Back to Notes
8 Easy
10 Medium
10 Hard

Topic-Specific Questions

Question 1
Easy
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("Before");
            int result = 10 / 0;
            System.out.println("After");
        } catch (ArithmeticException e) {
            System.out.println("Error: " + e.getMessage());
        }
        System.out.println("End");
    }
}
The line after the exception is not executed. Control jumps to the catch block.
Before
Error: / by zero
End
Question 2
Easy
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("Try");
        } catch (Exception e) {
            System.out.println("Catch");
        } finally {
            System.out.println("Finally");
        }
    }
}
No exception is thrown. Does the finally block still execute?
Try
Finally
Question 3
Easy
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            String s = null;
            System.out.println(s.length());
        } catch (NullPointerException e) {
            System.out.println("Caught NPE");
        }
    }
}
Calling a method on null throws NullPointerException.
Caught NPE
Question 4
Easy
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            int num = Integer.parseInt("123");
            System.out.println("Parsed: " + num);
        } catch (NumberFormatException e) {
            System.out.println("Not a number");
        }
    }
}
"123" is a valid integer string. Does an exception occur?
Parsed: 123
Question 5
Easy
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            int[] arr = new int[3];
            arr[0] = 10;
            arr[1] = 20;
            arr[2] = 30;
            System.out.println(arr[1]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Out of bounds");
        }
    }
}
All array indices (0, 1, 2) are valid for an array of size 3.
20
Question 6
Medium
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("A");
            int x = 10 / 0;
            System.out.println("B");
        } catch (ArithmeticException e) {
            System.out.println("C");
        } finally {
            System.out.println("D");
        }
        System.out.println("E");
    }
}
Trace the flow: try -> exception -> catch -> finally -> after.
A
C
D
E
Question 7
Medium
What is the output?
public class Main {
    static int divide(int a, int b) {
        return a / b;
    }
    public static void main(String[] args) {
        try {
            System.out.println(divide(10, 2));
            System.out.println(divide(10, 0));
            System.out.println(divide(20, 4));
        } catch (ArithmeticException e) {
            System.out.println("Division error");
        }
        System.out.println("Done");
    }
}
The second call throws. Does the third call execute?
5
Division error
Done
Question 8
Medium
What is the output?
public class Main {
    public static void main(String[] args) {
        for (String s : new String[]{"10", "abc", "20"}) {
            try {
                int n = Integer.parseInt(s);
                System.out.println("Parsed: " + n);
            } catch (NumberFormatException e) {
                System.out.println("Invalid: " + s);
            }
        }
    }
}
The try-catch is inside the loop. Each iteration is independent.
Parsed: 10
Invalid: abc
Parsed: 20
Question 9
Medium
What is the output?
public class Main {
    static int getValue() {
        try {
            System.out.println("try");
            return 1;
        } catch (Exception e) {
            System.out.println("catch");
            return 2;
        } finally {
            System.out.println("finally");
        }
    }
    public static void main(String[] args) {
        System.out.println("Value: " + getValue());
    }
}
finally executes even when there is a return in try.
try
finally
Value: 1
Question 10
Medium
What is the output?
class CustomException extends Exception {
    CustomException(String msg) { super(msg); }
}
public class Main {
    static void check(int x) throws CustomException {
        if (x < 0) throw new CustomException("Negative: " + x);
        System.out.println("Value: " + x);
    }
    public static void main(String[] args) {
        try {
            check(5);
            check(-3);
            check(10);
        } catch (CustomException e) {
            System.out.println("Caught: " + e.getMessage());
        }
    }
}
check(5) works. check(-3) throws. Does check(10) run?
Value: 5
Caught: Negative: -3
Question 11
Hard
What is the output?
public class Main {
    static void methodC() {
        System.out.println("C start");
        throw new RuntimeException("Error in C");
    }
    static void methodB() {
        System.out.println("B start");
        methodC();
        System.out.println("B end");
    }
    static void methodA() {
        System.out.println("A start");
        try {
            methodB();
        } catch (RuntimeException e) {
            System.out.println("Caught: " + e.getMessage());
        }
        System.out.println("A end");
    }
    public static void main(String[] args) {
        methodA();
    }
}
The exception propagates from C through B to A where it is caught.
A start
B start
C start
Caught: Error in C
A end
Question 12
Hard
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            try {
                throw new RuntimeException("inner");
            } catch (RuntimeException e) {
                System.out.println("Inner catch: " + e.getMessage());
                throw new RuntimeException("rethrown");
            } finally {
                System.out.println("Inner finally");
            }
        } catch (RuntimeException e) {
            System.out.println("Outer catch: " + e.getMessage());
        } finally {
            System.out.println("Outer finally");
        }
    }
}
The inner catch rethrows a new exception. Inner finally runs first, then outer catch.
Inner catch: inner
Inner finally
Outer catch: rethrown
Outer finally
Question 13
Hard
What is the output?
class Resource implements AutoCloseable {
    String name;
    Resource(String name) {
        this.name = name;
        System.out.println(name + " opened");
    }
    public void close() {
        System.out.println(name + " closed");
    }
}
public class Main {
    public static void main(String[] args) {
        try (Resource r1 = new Resource("A");
             Resource r2 = new Resource("B")) {
            System.out.println("Using resources");
            throw new RuntimeException("Failure");
        } catch (RuntimeException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
Resources are closed in reverse order before the catch block runs.
A opened
B opened
Using resources
B closed
A closed
Error: Failure
Question 14
Hard
What is the output?
public class Main {
    static String test() {
        String result = "initial";
        try {
            result = "try";
            return result;
        } finally {
            result = "finally";
        }
    }
    public static void main(String[] args) {
        System.out.println(test());
    }
}
The return value is evaluated before finally runs. Does changing result in finally affect the returned value?
try
Question 15
Hard
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            System.out.println("try");
            System.exit(0);
        } finally {
            System.out.println("finally");
        }
    }
}
System.exit() terminates the JVM. What happens to finally?
try
Question 16
Hard
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            throw new RuntimeException("first");
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
            throw new RuntimeException("second");
        } finally {
            System.out.println("finally");
            throw new RuntimeException("third");
        }
    }
}
An exception in finally replaces the exception from catch.
first
finally
Then the program terminates with RuntimeException: third

Mixed & Application Questions

Question 1
Easy
What is the difference between checked and unchecked exceptions?
Think about what the compiler requires.
Checked exceptions (subclasses of Exception, excluding RuntimeException) must be caught or declared with throws. The compiler enforces this. Unchecked exceptions (subclasses of RuntimeException) do not require handling. Checked exceptions represent recoverable conditions (file not found); unchecked exceptions represent programming errors (null pointer).
Question 2
Easy
What is the difference between throw and throws?
One is used inside the method body, the other in the method signature.
throw is used inside a method to explicitly throw an exception object: throw new Exception("error"). throws is used in the method signature to declare that the method might throw certain checked exceptions: void read() throws IOException.
Question 3
Easy
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            System.out.println(1);
            System.out.println(2);
            System.out.println(3);
        } catch (Exception e) {
            System.out.println("Error");
        }
        System.out.println(4);
    }
}
No exception is thrown. What happens?
1
2
3
4
Question 4
Medium
What is the output?
public class Main {
    public static void main(String[] args) {
        int x = 0;
        try {
            x = 1;
            int[] arr = null;
            x = arr.length;
            x = 2;
        } catch (NullPointerException e) {
            x = 3;
        } finally {
            x = 4;
        }
        System.out.println(x);
    }
}
Trace the value of x through try, catch, and finally.
4
Question 5
Medium
What is exception propagation?
Think about what happens when a method does not catch an exception.
Exception propagation is the process where an unhandled exception moves up the call stack from the method where it was thrown, through each calling method, until it finds a matching catch block. If no method catches it, the JVM prints the stack trace and terminates the program.
Question 6
Medium
What is the output?
public class Main {
    public static void main(String[] args) {
        try {
            String s = "Hello";
            char c = s.charAt(10);
        } catch (StringIndexOutOfBoundsException e) {
            System.out.println("String error");
        } catch (Exception e) {
            System.out.println("General error");
        }
    }
}
"Hello" has indices 0-4. Index 10 is out of bounds.
String error
Question 7
Medium
What is the output?
public class Main {
    static void risky() throws Exception {
        throw new Exception("Problem!");
    }
    
    static void caller() {
        try {
            risky();
        } catch (Exception e) {
            System.out.println("Handled: " + e.getMessage());
        }
    }
    
    public static void main(String[] args) {
        caller();
        System.out.println("Done");
    }
}
risky() declares throws Exception. caller() catches it.
Handled: Problem!
Done
Question 8
Hard
What is the output?
public class Main {
    static int count = 0;
    
    static void recursive() {
        count++;
        recursive();
    }
    
    public static void main(String[] args) {
        try {
            recursive();
        } catch (StackOverflowError e) {
            System.out.println("Stack overflow after " + count + " calls");
        }
    }
}
Infinite recursion causes StackOverflowError. Can it be caught?
Stack overflow after [some large number] calls
Question 9
Hard
When should you create a checked custom exception vs an unchecked custom exception?
Think about whether the caller can reasonably recover from the error.
Use a checked exception (extend Exception) when the caller can and should recover from the condition: insufficient funds, file not found, invalid input from an external source. Use an unchecked exception (extend RuntimeException) when the error represents a programming bug that should be fixed in the code: null argument, invalid state, assertion failure.
Question 10
Hard
What is the output?
public class Main {
    static void method() {
        try {
            throw new RuntimeException("A");
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
            throw new RuntimeException("B");
        } finally {
            System.out.println("finally");
        }
    }
    public static void main(String[] args) {
        try {
            method();
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
        }
    }
}
Exception B is thrown from catch. Finally runs before it propagates.
A
finally
B
Question 11
Medium
What is try-with-resources and what interface must a resource implement?
Think about automatic resource cleanup.
Try-with-resources (Java 7) is a try statement that declares one or more resources in its header. Resources are automatically closed when the try block exits, even if an exception occurs. Resources must implement the AutoCloseable interface (which has a single close() method).
Question 12
Hard
What is the output?
public class Main {
    public static void main(String[] args) {
        System.out.println(test());
    }
    static int test() {
        int x = 0;
        try {
            x = 1;
            return x;
        } finally {
            x = 2;
            return x;
        }
    }
}
The return in finally overrides the return in try.
2

Multiple Choice Questions

MCQ 1
Which block always executes regardless of whether an exception occurs?
  • A. try
  • B. catch
  • C. finally
  • D. throw
Answer: C
C is correct. The finally block always executes, whether an exception occurred or not, whether it was caught or not. The only exceptions are System.exit() and JVM crashes.
MCQ 2
Which of these is a checked exception?
  • A. NullPointerException
  • B. IOException
  • C. ArithmeticException
  • D. ArrayIndexOutOfBoundsException
Answer: B
B is correct. IOException is a checked exception (extends Exception, not RuntimeException). The other three are unchecked (subclasses of RuntimeException).
MCQ 3
What is the parent class of all exceptions and errors in Java?
  • A. Exception
  • B. Error
  • C. Throwable
  • D. Object
Answer: C
C is correct. Throwable is the root of the exception hierarchy. Both Exception and Error extend Throwable. While Object is the ultimate parent, Throwable is the root of throwable types.
MCQ 4
What does the throw keyword do?
  • A. Declares that a method might throw an exception
  • B. Explicitly throws an exception object
  • C. Catches an exception
  • D. Defines a custom exception class
Answer: B
B is correct. throw explicitly creates and throws an exception object: throw new Exception("error"). throws (with 's') is used in the method signature for declaration.
MCQ 5
NullPointerException is a:
  • A. Checked exception
  • B. Unchecked exception (RuntimeException)
  • C. Error
  • D. Compile-time error
Answer: B
B is correct. NullPointerException extends RuntimeException, making it an unchecked exception. The compiler does not force you to catch it.
MCQ 6
What interface must a resource implement to be used in try-with-resources?
  • A. Closeable
  • B. AutoCloseable
  • C. Serializable
  • D. Disposable
Answer: B
B is correct. Resources in try-with-resources must implement AutoCloseable (which has a close() method). Closeable extends AutoCloseable, so Closeable resources also work.
MCQ 7
What happens if a checked exception is neither caught nor declared with throws?
  • A. Runtime error
  • B. The exception is ignored
  • C. Compilation error
  • D. Warning only
Answer: C
C is correct. Checked exceptions must be either caught (try-catch) or declared (throws in signature). Failing to do either results in a compilation error.
MCQ 8
In multi-catch, which separator is used between exception types?
  • A. &&
  • B. ||
  • C. |
  • D. ,
Answer: C
C is correct. Multi-catch uses the pipe operator |: catch (IOException | SQLException e). The exception types must not have a parent-child relationship.
MCQ 9
To create a custom checked exception, you should extend:
  • A. RuntimeException
  • B. Exception
  • C. Throwable
  • D. Error
Answer: B
B is correct. Extending Exception creates a checked exception. Extending RuntimeException creates an unchecked exception. Extending Error is for JVM-level issues.
MCQ 10
What is exception propagation?
  • A. Catching all exceptions in one place
  • B. An unhandled exception traveling up the call stack
  • C. Converting checked exceptions to unchecked
  • D. Throwing multiple exceptions at once
Answer: B
B is correct. When a method does not catch an exception, it propagates to the calling method. This continues up the call stack until it is caught or the program terminates.
MCQ 11
What happens to the return value if finally has a return statement?
  • A. The try/catch return value is used
  • B. Both return values are returned
  • C. The finally return value overrides the try/catch return
  • D. Compilation error
Answer: C
C is correct. A return in the finally block overrides any return from try or catch. This is confusing behavior, which is why returning from finally is strongly discouraged.
MCQ 12
Can you have a try block without a catch block?
  • A. No, catch is required
  • B. Yes, if there is a finally block
  • C. Yes, always
  • D. Only with try-with-resources
Answer: B
B is correct. A try block must be followed by either a catch block, a finally block, or both. try { } finally { } is valid. Also, try-with-resources can omit both catch and finally.
MCQ 13
What exception does Integer.parseInt("abc") throw?
  • A. ArithmeticException
  • B. NumberFormatException
  • C. ClassCastException
  • D. IllegalArgumentException
Answer: B
B is correct. parseInt throws NumberFormatException when the string cannot be parsed as an integer. NumberFormatException is a subclass of IllegalArgumentException.
MCQ 14
In try-with-resources with multiple resources, what order are they closed?
  • A. In the order they were declared
  • B. In reverse order of declaration
  • C. Random order
  • D. All at once
Answer: B
B is correct. Resources in try-with-resources are closed in reverse order of their declaration. This matches the stack-like nature of resource acquisition (last acquired, first released).
MCQ 15
Which of the following is TRUE about Error in Java?
  • A. Errors must be caught like checked exceptions
  • B. Errors represent recoverable conditions
  • C. Errors indicate serious problems not meant to be caught by applications
  • D. Errors extend RuntimeException
Answer: C
C is correct. Error represents serious JVM-level problems (OutOfMemoryError, StackOverflowError) that applications should not attempt to catch. They extend Throwable, not RuntimeException.
MCQ 16
What is the purpose of the getMessage() method in exceptions?
  • A. It prints the stack trace
  • B. It returns the detail message string of the exception
  • C. It returns the exception class name
  • D. It re-throws the exception
Answer: B
B is correct. getMessage() returns the detail message string passed to the exception's constructor. For new Exception("file not found"), getMessage() returns "file not found".

Coding Challenges

Challenge 1: Safe Division Calculator

Easy
Write a method safeDivide(int a, int b) that returns the result of a/b. If b is 0, catch the ArithmeticException and return -1. Test with (10,2), (10,0), (20,4).
Sample Input
(10,2), (10,0), (20,4)
Sample Output
10 / 2 = 5 10 / 0 = -1 (division by zero) 20 / 4 = 5
Use try-catch. Return -1 on error.
public class Main {
    static int safeDivide(int a, int b) {
        try {
            return a / b;
        } catch (ArithmeticException e) {
            return -1;
        }
    }
    public static void main(String[] args) {
        int[][] tests = {{10,2}, {10,0}, {20,4}};
        for (int[] t : tests) {
            int result = safeDivide(t[0], t[1]);
            if (result == -1) {
                System.out.println(t[0] + " / " + t[1] + " = -1 (division by zero)");
            } else {
                System.out.println(t[0] + " / " + t[1] + " = " + result);
            }
        }
    }
}

Challenge 2: Input Validator with Custom Exceptions

Medium
Create two custom exceptions: InvalidAgeException and InvalidNameException. Write a method registerStudent(String name, int age) that throws InvalidNameException if name is null/empty, and InvalidAgeException if age is not between 5 and 25. Test with valid and invalid inputs.
Sample Input
('Arjun', 20), ('', 20), ('Kavya', -5), (null, 30)
Sample Output
Registered: Arjun, age 20 Error: Name cannot be empty Error: Invalid age: -5. Must be between 5 and 25 Error: Name cannot be null
Custom exceptions must extend Exception (checked). Include meaningful messages.
class InvalidAgeException extends Exception {
    InvalidAgeException(int age) {
        super("Invalid age: " + age + ". Must be between 5 and 25");
    }
}

class InvalidNameException extends Exception {
    InvalidNameException(String reason) {
        super(reason);
    }
}

public class Main {
    static void registerStudent(String name, int age) throws InvalidNameException, InvalidAgeException {
        if (name == null) throw new InvalidNameException("Name cannot be null");
        if (name.isEmpty()) throw new InvalidNameException("Name cannot be empty");
        if (age < 5 || age > 25) throw new InvalidAgeException(age);
        System.out.println("Registered: " + name + ", age " + age);
    }

    public static void main(String[] args) {
        Object[][] tests = {{"Arjun", 20}, {"", 20}, {"Kavya", -5}, {null, 30}};
        for (Object[] t : tests) {
            try {
                registerStudent((String) t[0], (int) t[1]);
            } catch (InvalidNameException | InvalidAgeException e) {
                System.out.println("Error: " + e.getMessage());
            }
        }
    }
}

Challenge 3: Resource Manager with AutoCloseable

Medium
Create a class ConnectionPool implementing AutoCloseable. It has a constructor that prints 'Pool opened with N connections', a method getConnection(int id) that throws RuntimeException if id > pool size, and close() that prints 'Pool closed'. Demonstrate try-with-resources with normal use and with an exception.
Sample Input
Pool size=3, get connections 1, 2, 5
Sample Output
Pool opened with 3 connections Connection 1 acquired Connection 2 acquired Pool closed Error: Connection 5 exceeds pool size 3
Implement AutoCloseable. Use try-with-resources.
class ConnectionPool implements AutoCloseable {
    int size;
    ConnectionPool(int size) {
        this.size = size;
        System.out.println("Pool opened with " + size + " connections");
    }
    void getConnection(int id) {
        if (id > size) throw new RuntimeException("Connection " + id + " exceeds pool size " + size);
        System.out.println("Connection " + id + " acquired");
    }
    @Override
    public void close() {
        System.out.println("Pool closed");
    }
}

public class Main {
    public static void main(String[] args) {
        try (ConnectionPool pool = new ConnectionPool(3)) {
            pool.getConnection(1);
            pool.getConnection(2);
            pool.getConnection(5);
        } catch (RuntimeException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Challenge 4: Exception Chain Logger

Hard
Write three methods: parseData() throws NumberFormatException, processData() calls parseData and wraps the exception in a custom DataProcessingException (with the original as cause), and main() catches DataProcessingException and prints both the message and the root cause.
Sample Input
Input: "abc"
Sample Output
Processing error: Failed to process data Root cause: NumberFormatException: For input string: "abc"
Use exception chaining (pass cause to constructor). Access with getCause().
class DataProcessingException extends Exception {
    DataProcessingException(String msg, Throwable cause) {
        super(msg, cause);
    }
}

public class Main {
    static int parseData(String input) {
        return Integer.parseInt(input);
    }

    static int processData(String input) throws DataProcessingException {
        try {
            return parseData(input);
        } catch (NumberFormatException e) {
            throw new DataProcessingException("Failed to process data", e);
        }
    }

    public static void main(String[] args) {
        try {
            processData("abc");
        } catch (DataProcessingException e) {
            System.out.println("Processing error: " + e.getMessage());
            System.out.println("Root cause: " + e.getCause().getClass().getSimpleName() + ": " + e.getCause().getMessage());
        }
    }
}

Challenge 5: Bank Transaction System

Hard
Create a BankAccount class with methods deposit(double) and withdraw(double). Withdraw throws InsufficientFundsException (custom checked) if amount > balance. Write a transfer(BankAccount from, BankAccount to, double amount) method. If withdraw fails, the transfer should be atomic (no partial changes). Test with successful and failed transfers.
Sample Input
Account A: 5000, Account B: 3000, Transfer 2000 then 5000
Sample Output
Transfer of 2000.0: Success A: 3000.0, B: 5000.0 Transfer of 5000.0: Failed - Insufficient funds. Deficit: 2000.0 A: 3000.0, B: 5000.0
Ensure atomicity: if withdraw fails, no changes should persist.
class InsufficientFundsException extends Exception {
    double deficit;
    InsufficientFundsException(double deficit) {
        super("Insufficient funds. Deficit: " + deficit);
        this.deficit = deficit;
    }
}

class BankAccount {
    String name;
    double balance;
    BankAccount(String name, double balance) {
        this.name = name;
        this.balance = balance;
    }
    void deposit(double amount) { balance += amount; }
    void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) throw new InsufficientFundsException(amount - balance);
        balance -= amount;
    }
}

public class Main {
    static void transfer(BankAccount from, BankAccount to, double amount) {
        try {
            from.withdraw(amount);
            to.deposit(amount);
            System.out.println("Transfer of " + amount + ": Success");
        } catch (InsufficientFundsException e) {
            System.out.println("Transfer of " + amount + ": Failed - " + e.getMessage());
        }
        System.out.println(from.name + ": " + from.balance + ", " + to.name + ": " + to.balance);
    }

    public static void main(String[] args) {
        BankAccount a = new BankAccount("A", 5000);
        BankAccount b = new BankAccount("B", 3000);
        transfer(a, b, 2000);
        transfer(a, b, 5000);
    }
}

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to learn Java with a live mentor?

Explore our Java Masterclass