Site Search:

Create custom exceptions and Auto-closeable resources

Back>

auto-closeable
auto-closeable


There are the constructors for Exception class:
Constructors
ModifierConstructor and Description
Exception()
Constructs a new exception with null as its detail message.
Exception(String message)
Constructs a new exception with the specified detail message.
Exception(String message, Throwable cause)
Constructs a new exception with the specified detail message and cause.
protectedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)
Constructs a new exception with the specified detail message, cause, suppression enabled or disabled, and writable stack trace enabled or disabled.
Exception(Throwable cause)
Constructs a new exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which typically contains the class and detail message of cause).

The following example shows the usage:

OCPJP>cat ExceptionDemo.java 
import java.io.IOException;

public class ExceptionDemo {
    public static void main(String...args) {
        try {
            throw new Exception();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        try {
            throw new Exception("message only");
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        try {
            throw new Exception(new IOException());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        try {
            throw new Exception("message and type", new IOException());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
OCPJP>
OCPJP>
OCPJP>javac ExceptionDemo.java 
OCPJP>java ExceptionDemo
java.lang.Exception
at ExceptionDemo.main(ExceptionDemo.java:6)
java.lang.Exception: message only
at ExceptionDemo.main(ExceptionDemo.java:12)
java.lang.Exception: java.io.IOException
at ExceptionDemo.main(ExceptionDemo.java:18)
Caused by: java.io.IOException
... 1 more
java.lang.Exception: message and type
at ExceptionDemo.main(ExceptionDemo.java:24)
Caused by: java.io.IOException
... 1 more
OCPJP>


try-with-resources automatically closes any resources opened in the try clause. In order for a class to be created in the try clause, the class have to implement an AutoCloseable interface.

void close()
    throws Exception

This method throws Exception, means the implementing class can throw checked Exception, RuntimeException or no exception at all.

OCPJP>cat AutoCloseableDemo.java 
import java.io.IOException;

class AutoCloseableImpl implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("AutoCloseableImpl do nothing");
    }
}

class AutoCloseableImpl2 implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("AutoCloseableImpl do nothing but declares Exception and force a catch");
    }
}

public class AutoCloseableDemo {
    public static void main(String[] args) {
        try(AutoCloseableImpl autoCloseableImpl = new AutoCloseableImpl()) {
            System.out.println("do nothing");
        }
        
        try(AutoCloseable autoCloseableImpl = new AutoCloseableImpl2();) {
            System.out.println("do nothing");
        } catch (Exception e) {
            //must have in order to compile
            e.printStackTrace();
        }
        
        try(AutoCloseableImpl autoCloseableImpl = new AutoCloseableImpl()) {
            System.out.println("do nothing");
        } catch (Exception e) {
            //optional block
        }
        
        try(AutoCloseable autoCloseableImpl = new AutoCloseable() {
            @Override
            public void close() {
                System.out.println("anonymous class do nothing");
            }
        }) {
            System.out.println("do nothing");
        } catch (Exception e) {
            // must have in order to compile
            e.printStackTrace();
        }
        
        class AutoCloseableImpl3 implements AutoCloseable {
            @Override
            public void close() {
                System.out.println("local class do nothing");
            }
        }
        
        try(AutoCloseableImpl3 autoCloseableImpl = new AutoCloseableImpl3()) {
            System.out.println("do nothing");
        }
        
        try(AutoCloseable autoCloseableImpl = new AutoCloseableImpl3()) {
            System.out.println("do nothing");
        } catch (Exception e) {
            // must have in order to compile
            e.printStackTrace();
        }
        
        class AutoCloseableImpl4 implements AutoCloseable {
            @Override
            public void close() throws RuntimeException {
                System.out.println("local class do nothing but declaring RuntimeException");
            }
        }
        
        try(AutoCloseableImpl4 autoCloseable = new AutoCloseableImpl4()) {
            System.out.println("do nothing");
        }
        
        class AutoCloseableImpl5 implements AutoCloseable {
            @Override
            public void close() throws IOException {
                System.out.println("local class do nothing but declaring checked Exception and force catch");
            }
        }
         
        try(AutoCloseableImpl5 autoCloseable = new AutoCloseableImpl5()) {
            System.out.println("do nothing");
        } catch (IOException e) {
            //must have in order to compile
            e.printStackTrace();
        }
        
        class AutoCloseableImpl6 implements AutoCloseable {
            @Override
            public void close() {
                System.out.println("local class do nothing but throws RuntimeException");
                throw new RuntimeException("don't have to catch me, I stop the program");
            }
        }
        
        try(AutoCloseableImpl6 autoCloseable = new AutoCloseableImpl6()) {
            System.out.println("do nothing"); 
        } catch (Exception e) {
            //optional block
            e.printStackTrace();
        }
        
        class AutoCloseableImpl7 implements AutoCloseable {
            @Override
            public void close() throws Exception {
                System.out.println("local class do nothing but throws checked Exception");
                throw new IOException("must catch me or throw me");
            }
        }
        
        try(AutoCloseableImpl7 autoCloseable = new AutoCloseableImpl7()) {
            System.out.println("do nothing"); 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
OCPJP>
OCPJP>
OCPJP>
OCPJP>javac AutoCloseableDemo.java 
OCPJP>java AutoCloseableDemo
do nothing
AutoCloseableImpl do nothing
do nothing
AutoCloseableImpl do nothing but declares Exception and force a catch
do nothing
AutoCloseableImpl do nothing
do nothing
anonymous class do nothing
do nothing
local class do nothing
do nothing
local class do nothing
do nothing
local class do nothing but declaring RuntimeException
do nothing
local class do nothing but declaring checked Exception and force catch
do nothing
local class do nothing but throws RuntimeException
java.lang.RuntimeException: don't have to catch me, I stop the program
at AutoCloseableDemo$1AutoCloseableImpl6.close(AutoCloseableDemo.java:95)
at AutoCloseableDemo.main(AutoCloseableDemo.java:101)
do nothing
local class do nothing but throws checked Exception
java.io.IOException: must catch me or throw me
at AutoCloseableDemo$1AutoCloseableImpl7.close(AutoCloseableDemo.java:110)
at AutoCloseableDemo.main(AutoCloseableDemo.java:116)
OCPJP>


Things get tricky when the exceptions are throw from a resource class in try clause and a statement inside try block. Let's take a look at what is Suppressed Exceptions.

OCPJP>cat SuppressedExceptionDemo.java 
import java.io.IOException;
import java.sql.SQLException;

public class SuppressedExceptionDemo {
    class AutoCloseableImpl implements AutoCloseable {
        int id = 0;
        AutoCloseableImpl(int id) {
            this.id = id;
        }
        
        AutoCloseableImpl() {}
        
        @Override
        public void close() throws IOException {
            throw new IOException("from AutoCloseableImpl" + id);
        }
    }
    
    public static void main(String...args) {
        //inner class initialization syntax: new Outer().new Inner()
        try(AutoCloseableImpl autoCloseableImpl = new SuppressedExceptionDemo().new AutoCloseableImpl()) {
            System.out.println();
            System.out.println("case 1, normal Exception from AutoCloseable");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        try(AutoCloseableImpl autoCloseableImpl = new SuppressedExceptionDemo().new AutoCloseableImpl()) {
            System.out.println();
            System.out.println("case 2, Exception from AutoCloseable is suppressed by Exception throw from try statements");
            throw new IOException("======from try statement, primary exception=====");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        }
        
        try(AutoCloseableImpl autoCloseableImpl = new SuppressedExceptionDemo().new AutoCloseableImpl()) {
            System.out.println();
            System.out.println("case 3, Exception from AutoCloseable is suppressed by Exception throw from try statements");
            throw new SQLException("======from try statement, primary exception=====");
        } catch (IOException | SQLException e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        }
        
        try(AutoCloseableImpl autoCloseableImpl = new SuppressedExceptionDemo().new AutoCloseableImpl()) {
            System.out.println();
            System.out.println("case 3-1, Exception from AutoCloseable is suppressed by Exception throw from try statements");
            throw new SQLException("======from try statement, primary exception=====");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        }
        
        try(AutoCloseableImpl autoCloseableImpl = new SuppressedExceptionDemo().new AutoCloseableImpl()) {
            System.out.println();
            System.out.println("case 3-2, Exception from AutoCloseable is suppressed by Exception throw from try statements");
            throw new SQLException("======from try statement, primary exception=====");
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        } 
        
        try(AutoCloseableImpl autoCloseableImpl = new SuppressedExceptionDemo().new AutoCloseableImpl()) {
            System.out.println();
            System.out.println("case 4, Exception from AutoCloseable is suppressed by Exception throw from try statements");
            throw new IllegalStateException("======from try statement, primary exception2=====");
        } catch (Exception e) {
            e.printStackTrace();
            for(Throwable t : e.getSuppressed()) {
                System.out.println("e.getMessage(): " + e.getMessage());
            }
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        }
        
        try(AutoCloseableImpl autoCloseableImpl1 = new SuppressedExceptionDemo().new AutoCloseableImpl(1);
            AutoCloseableImpl autoCloseableImpl2 = new SuppressedExceptionDemo().new AutoCloseableImpl(2)) {
            System.out.println();
            System.out.println("case 5, Exception from earlier AutoCloseable is suppressed by Exception throws from later AutoCloseable");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        }
        
        try(AutoCloseableImpl autoCloseableImpl1 = new SuppressedExceptionDemo().new AutoCloseableImpl(1);
            AutoCloseableImpl autoCloseableImpl2 = new SuppressedExceptionDemo().new AutoCloseableImpl(2)) {
            System.out.println();
            System.out.println("case 5-1, Exception from earlier AutoCloseable is suppressed by Exception throws from later AutoCloseable");
            throw new RuntimeException("=====from try statement, primary exception3=====");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("number of suppressed exception: " + e.getSuppressed().length);
        }
    }

}
OCPJP>
OCPJP>
OCPJP>javac SuppressedExceptionDemo.java 
OCPJP>java SuppressedExceptionDemo

case 1, normal Exception from AutoCloseable
java.io.IOException: from AutoCloseableImpl0
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:24)

case 2, Exception from AutoCloseable is suppressed by Exception throw from try statements
java.io.IOException: ======from try statement, primary exception=====
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:31)
Suppressed: java.io.IOException: from AutoCloseableImpl0
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:32)
number of suppressed exception: 1

case 3, Exception from AutoCloseable is suppressed by Exception throw from try statements
java.sql.SQLException: ======from try statement, primary exception=====
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:40)
Suppressed: java.io.IOException: from AutoCloseableImpl0
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:41)
number of suppressed exception: 1

case 3-1, Exception from AutoCloseable is suppressed by Exception throw from try statements
java.sql.SQLException: ======from try statement, primary exception=====
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:49)
Suppressed: java.io.IOException: from AutoCloseableImpl0
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:50)
number of suppressed exception: 1

case 3-2, Exception from AutoCloseable is suppressed by Exception throw from try statements
java.sql.SQLException: ======from try statement, primary exception=====
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:61)
Suppressed: java.io.IOException: from AutoCloseableImpl0
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:62)
number of suppressed exception: 1

case 4, Exception from AutoCloseable is suppressed by Exception throw from try statements
java.lang.IllegalStateException: ======from try statement, primary exception2=====
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:73)
Suppressed: java.io.IOException: from AutoCloseableImpl0
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:74)
e.getMessage(): ======from try statement, primary exception2=====
number of suppressed exception: 1

case 5, Exception from earlier AutoCloseable is suppressed by Exception throws from later AutoCloseable
java.io.IOException: from AutoCloseableImpl2
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:86)
Suppressed: java.io.IOException: from AutoCloseableImpl1
... 2 more
number of suppressed exception: 1

case 5-1, Exception from earlier AutoCloseable is suppressed by Exception throws from later AutoCloseable
java.lang.RuntimeException: =====from try statement, primary exception3=====
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:95)
Suppressed: java.io.IOException: from AutoCloseableImpl2
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:96)
Suppressed: java.io.IOException: from AutoCloseableImpl1
at SuppressedExceptionDemo$AutoCloseableImpl.close(SuppressedExceptionDemo.java:15)
at SuppressedExceptionDemo.main(SuppressedExceptionDemo.java:96)
number of suppressed exception: 2
OCPJP>


When a finally block is added to the above scenario, and an exception is thrown inside the finally block, things get even trickier. The previous exception is lost.

OCPJP>cat LostExceptionDemo.java 
import java.io.IOException;

final class AutoCloseableImple implements AutoCloseable {
    private final int id;
    public AutoCloseableImple(int id) {this.id = id;}

    @Override
    public void close() {
        System.out.println("close " + id);
        throw new RuntimeException("from AutoCloseable " + id);
    }
}

public class LostExceptionDemo {
    public static void main(String...args) {
        try(AutoCloseable auto1 = new AutoCloseableImple(1);
                AutoCloseable auto2 = new AutoCloseableImple(2)) {
            System.out.println("try...");
            throw new RuntimeException("from try statement");
        } catch (IOException e) {
            System.out.println("catch...");
            e.printStackTrace(); //this line if hit, print out suppressed exceptions
        } finally {
            System.out.println("finally...");
            throw new RuntimeException("I swallow them all, without any suppressed exceptions");
        }
    }
}
OCPJP>
OCPJP>javac LostExceptionDemo.java 
OCPJP>java LostExceptionDemo
try...
close 2
close 1
finally...
Exception in thread "main" java.lang.RuntimeException: I swallow them all, without any suppressed exceptions
at LostExceptionDemo.main(LostExceptionDemo.java:25)

OCPJP>


Two more test points:

  • Resources are closed after the try clause ends and before any catch/finally causes.
  • Resources are closed in the reverse order from which they are created.