try-catch-finally

  • Any exception thrown from try block makes the control jump to catch block if it is caught by it
  • At least either catch or finally should be present with try
  • There can only be one finally but there can be multiple catch blocks
  • No matter whether exception is handled or not, or return statement is present or not, finally will ALWAYS execute
  • finally will not get executed if:
    • System.exit() is called in try or catch block
    • JVM is shutdown abruptly
  • return statement in finally block will always override try or catch’s return statement if present
  • The exception thrown from code in the try block, tries to find the first match in multiple catch blocks and executes it and then goes directly to finally block.
    • It is good practice is to go from specific exception to more generic one when specifying multiple catch blocks
    • It is compile time error if we write catch with general exception before catch with specific exception
try {
    // do something
} catch(Exception e) {
    // handle error
} finally {
    // code executes at last always
}
 
int fun() {
    try {
        return 0;
    } catch (Exception e) {
        // nothing
    } finally {
        System.out.println("Finally executes");
    }
}
 
System.out.println(fun());
// --Output--
// Finally executes
// 0
 
int fun2() {
    try {
        return 0;
    } catch (Exception e) {
        //
    } finally {
        System.out.println("Finally executes");
        return 50; // overrides try's return statement
    }
}
 
System.out.println(fun2());
// --Output--
// Finally executes
// 50
 
int fun3() {
    try {
        throw new NullPointerException();
    } catch (Exception e) {
        System.out.println("In Exception...");
        System.exit(0);
    } finally {
        System.out.println("Finally executes");
    }
}
 
System.out.println(fun3());
// --Output--
// In Exception...

Handle multiple exceptions in single catch block

  • Using pipe (|) symbol
try {
    // ....
} catch (IOException | SQLException e) {
    // .....
}

Exceptions in catch and finally block

try {
    System.out.println("Work starts");
    throw new RuntimeException("try throws exception");
} catch (Exception e) {
    System.out.println("catch caught the Exception");
    // eventually discarded because finally also throws exception
    throw new RuntimeException("catch throws exception");
} finally {
    System.out.println("finally executes");
    throw new RuntimeException("finally throws exception");
}
 
// -- Output --
// Work starts
// Exception in thread "main" catch caught the Exception
// finally executes
// java.lang.RuntimeException: finally throws exception

try-with-resources

try (JpegReader jpegReader = new JpegReader();  
     PngReader pngReader = new PngReader()) {
    // your code
}
  • In a try-with-resources statement, any catch or finally block is run after the resources declared have been closed
  • close() methods are called automatically in opposite order of their creation
    • pngReader.close() is called first, then jpegReader.close() is called
  • If the resource is evaluated to null in declaration, then close() method is not called internally, but you need to make sure it is not null when using inside try block
  • Following exceptions can be caught in the catch block:
    • If exception happen in resource declarations, then it is thrown
    • If exception happen in try-with-resource close methods, then it is thrown
    • If exception happen in try-with-resource close methods AND inside try block, then try block exception is thrown and try-with-resource’s exception is suppressed
class JpegReader implements AutoCloseable {
    public String read() {
        return "Anna.jpeg";
    }
 
    @Override
    public void close() {
        System.out.println("JpegReader close is invoked");
    }
}
 
class PngReader implements AutoCloseable {
    public String read() {
        return "Anna.png";
    }
 
    @Override
    public void close() {
        System.out.println("PngReader close is invoked");
        // this exception is suppressed
        // because there is already an exception in try block
        throw new RuntimeException("failed to close PngReader");
    }
}
 
public class Test {  
    public static void main(String[] args) {  
          try (JpegReader jpegReader = new JpegReader();  
             PngReader pngReader = new PngReader()) {  
            System.out.println(jpegReader.read());  
            System.out.println(pngReader.read());  
            throw new RuntimeException("try failed");  
        } catch (Exception e) {  
            System.out.println(e.getMessage());
            // print suppressed exception
            System.out.println(e.getSuppressed()[0].getMessage());
        }
    }  
}
  • Output
Anna.jpeg
Anna.png
PngReader close is invoked
JpegReader close is invoked
try failed
failed to close PngReader

try-finally vs try-with-resource

  • try-with-resource is better than try-finally construct
  • It is possible that jpegReader.close() throws some exception in finally block
  • This will cause resource leak of pngReader since it was not closed
JpegReader jpegReader = new JpegReader();  
 PngReader pngReader = new PngReader()
try {
    return jpegReader.readLine();
} finally {
    jpegReader.close(); // if it fails, pngReader.close() is not executed
    pngReader.close();
}

Closable vs AutoClosable

  • Closeable extends AutoCloseable
CloseableAutoCloseable
close() throws IOExceptionclose() throws Exception
subclass must throw specialized exceptions of IOExceptionsubclass can throw any exception