Menu
CoddyTech

Java Exception Handling Interview Questions

Checked versus unchecked exceptions, finally, try-with-resources and custom exceptions.

10 questions
  1. What is the difference between checked and unchecked exceptions?

    Checked exceptions (Exception subclasses outside RuntimeException, like IOException) must be caught or declared with throws. Unchecked ones (RuntimeException subclasses like NullPointerException, plus Error) need neither.

    Checked usually means a condition the caller can recover from, unchecked a bug. An Error such as OutOfMemoryError should normally not be caught. More in the exceptions guide.

  2. What is the difference between throw and throws?

    throw throws one exception object; throws in a signature declares what a method may pass up, and is required only for checked exceptions.

    Java
    public class Main {
        static int parseAge(String s) throws NumberFormatException {   // declares
            int age = Integer.parseInt(s);
            if (age < 0) {
                throw new IllegalArgumentException("age < 0: " + age);  // throws
            }
            return age;
        }
    
        public static void main(String[] args) {
            for (String input : new String[] {"30", "-4", "abc"}) {
                try {
                    System.out.println("ok " + parseAge(input));
                } catch (IllegalArgumentException e) {
                    System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage());
                }
            }
        }
    }

    It prints ok 30, IllegalArgumentException: age < 0: -4 and NumberFormatException: For input string: "abc". One catch handles both because NumberFormatException extends IllegalArgumentException.

  3. Does finally run when the try block returns?

    Java
    public class Main {
        static int f() {
            try {
                return 1;
            } finally {
                System.out.print("finally ");
            }
        }
    
        public static void main(String[] args) {
            System.out.println(f());
        }
    }

    It prints finally 1. return 1 computes its value, finally runs, and then the method returns.

    Follow-up: does finally always run? Not if the JVM stops inside the try, as with System.exit(), a crash, or a daemon thread at shutdown.

  4. What happens with a return in both try and finally?

    Java
    public class Main {
        static int f() {
            try {
                return 1;
            } finally {
                return 2;
            }
        }
    
        public static void main(String[] args) {
            System.out.println(f());
        }
    }

    It prints 2. A return in finally replaces the try's return value and would also swallow an exception from the try, so linters flag it. Use finally only for cleanup.

  5. What is try-with-resources and in what order are resources closed?

    Resources declared in try (...) are closed automatically when the block ends, in reverse order and before any catch runs; anything AutoCloseable works.

    Java
    class Res implements AutoCloseable {
        private final String name;
        Res(String name) { this.name = name; System.out.println("open " + name); }
        @Override
        public void close() { System.out.println("close " + name); }
    }
    
    public class Main {
        public static void main(String[] args) {
            try (Res a = new Res("A"); Res b = new Res("B")) {
                System.out.println("body");
                throw new IllegalStateException("boom");
            } catch (IllegalStateException e) {
                System.out.println("caught " + e.getMessage());
            }
        }
    }

    It prints open A, open B, body, close B, close A, caught boom. An exception thrown by close() is attached to the main one as suppressed (e.getSuppressed()) instead of replacing it.

  6. How do you create a custom exception in Java?

    Extend Exception (checked) or RuntimeException (unchecked) and pass the message to super.

    Java
    class InsufficientFundsException extends RuntimeException {
        InsufficientFundsException(int balance, int amount) {
            super("balance " + balance + ", tried to withdraw " + amount);
        }
    }
    
    public class Main {
        static int balance = 500;
    
        static void withdraw(int amount) {
            if (amount > balance) throw new InsufficientFundsException(balance, amount);
            balance -= amount;
        }
    
        public static void main(String[] args) {
            try {
                withdraw(200);
                withdraw(400);
            } catch (InsufficientFundsException e) {
                System.out.println("Failed: " + e.getMessage());
            }
        }
    }

    It prints Failed: balance 300, tried to withdraw 400. When wrapping another exception, pass it as the cause (super(message, cause)) to keep its stack trace. See try-catch.

  7. What causes a NullPointerException and how do you avoid it?

    A NullPointerException is thrown when a null reference is used as an object: a method call, a field read, an array index or unboxing.

    Prevent it with Objects.requireNonNull on inputs, empty collections or Optional instead of null returns, "yes".equals(input), and map.getOrDefault. Since Java 15 the message names the null expression by default (local variable names only when compiled with -g; see JEP 358). More in NullPointerException.

  8. Can one catch block handle several exceptions, and does the order of catch blocks matter?

    Yes to both. Since Java 7 a multi-catch (catch (A | B e)) handles several unrelated types in one block, and e is implicitly final. Order matters because the first matching catch wins: a subclass must come before its superclass, or the compiler rejects the later block with "exception has already been caught".

    Java
    import java.io.FileNotFoundException;
    
    public class Main {
        static void risky(int n) throws Exception {
            if (n == 1) throw new FileNotFoundException("config.txt");
            if (n == 2) throw new NumberFormatException("abc");
            throw new Exception("generic");
        }
    
        public static void main(String[] args) {
            for (int n = 1; n <= 3; n++) {
                try {
                    risky(n);
                } catch (FileNotFoundException | NumberFormatException e) {   // multi-catch
                    System.out.println("specific: " + e.getClass().getSimpleName());
                } catch (Exception e) {   // the broader type must come last
                    System.out.println("general: " + e.getMessage());
                }
            }
        }
    }

    It prints specific: FileNotFoundException, specific: NumberFormatException and general: generic. The types in one multi-catch cannot be subclasses of each other either.

  9. What is exception chaining in Java, and why wrap a low-level exception?

    Exception chaining wraps a caught exception as the cause of a new one, so the caller gets an error in its own terms while the original stack trace survives. Pass the cause to the constructor (super(message, cause)) or call initCause.

    Java
    class ConfigException extends Exception {
        ConfigException(String message, Throwable cause) { super(message, cause); }
    }
    
    public class Main {
        static int readPort(String raw) throws ConfigException {
            try {
                return Integer.parseInt(raw);
            } catch (NumberFormatException e) {
                throw new ConfigException("bad port in config", e);   // keep the cause
            }
        }
    
        public static void main(String[] args) {
            try {
                readPort("80a");
            } catch (ConfigException e) {
                System.out.println(e.getMessage());
                System.out.println("cause: " + e.getCause());
            }
        }
    }

    It prints bad port in config and cause: java.lang.NumberFormatException: For input string: "80a". An uncaught chained exception prints both traces, the original under Caused by:. The common mistake is throw new ConfigException(e.getMessage()), which drops the original trace.

  10. Can an overriding method throw a broader checked exception than the method it overrides?

    No. An overriding method may declare the same checked exceptions, narrower ones, or none, but not new or broader checked ones. Unchecked exceptions are not restricted. The reason is substitution: code holding a Reader reference handles only what Reader.read() declares.

    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    class Reader {
        void read() throws IOException { }
    }
    
    class LocalReader extends Reader {
        @Override
        void read() throws FileNotFoundException { }   // OK: narrower
    }
    
    class NetReader extends Reader {
        @Override
        void read() throws Exception { }   // compile error: broader
    }
    

    javac rejects NetReader with "overridden method does not throw Exception". The same rule applies to a class implementing an interface method.

Coddy programming languages illustration

Learn to code with Coddy

Get started