Class Closer<E extends Exception>

  • Type Parameters:
    E - The supertype of exceptions this closer can catch and re-throw, besides RuntimeException and Error.
    All Implemented Interfaces:
    AutoCloseable

    public final class Closer<E extends Exception>
    extends AbstractCloser<Closer<E>,​E>
    implements AutoCloseable
    A helper for closing multiple resources and re-throwing only one exception, suppressing the others as necessary.

    This class is not thread safe.

    This helper is mainly useful when implementing AutoCloseable.close() or a similar closing method in your own class, to make sure that all resources are at least given the chance to close, even if closing one of them fails. When creating then closing resources in the scope of a single method call, try-with-resource blocks should be favored.

    See the AbstractCloser superclass for a list of methods allowing to close objects while catching exceptions.

    Warning: In order not to ignore exceptions, you should always call close() once you closed all of your resources. The most straightforward way to do this is to use a try-with-resource block:

    
     public void myCloseFunction() throws MyException {
       try ( Closer<MyException> closer = new Closer<>() ) {
         closer.push( this.myCloseable::close );
         closer.pushAll( this.myListOfCloseables, MyCloseableType::close );
       }
     }
     

    Exception type

    Note that the closer has a generic type parameter, allowing it to re-throw a given checked exception. If you don't want to use this feature, you can simply use a Closer<RuntimeException>.

    Splitting

    If you need to close multiple resources throwing different checked exceptions, and those exceptions don't have a practical common superclass, you can "split" the closer:

    
     public void myCloseFunction() throws IOException, MyException, MyOtherException {
       try ( Closer<MyException> closer1 = new Closer<>();
           Closer<IOException> closer2 = closer1.split();
           Closer<MyOtherException> closer3 = closer1.split() ) {
         closer2.push( this.someJavaIOCloseable::close );
         closer1.pushAll( this.myListOfCloseables1, MyCloseableTypeThrowingMyException::close );
         closer3.pushAll( this.myListOfCloseables2, MyCloseableTypeThrowingMyOtherException::close );
       }
     }
     

    The multiple closers will share the same state, which means the first exception to be caught by any of the closers will be the one to be re-thrown, and all subsequent exceptions caught by any closer will be added as suppressed to this first exception. Be careful though, you will have to close every single closer. Closing just the original one will not be enough.

    • Constructor Detail

      • Closer

        public Closer()
    • Method Detail

      • split

        public <E2 extends ExceptionCloser<E2> split()
        Returns:
        A closer sharing the same state as this, allowing to handle multiple exception types.
        See Also:
        splitting
      • close

        public void close()
                   throws E extends Exception
        Specified by:
        close in interface AutoCloseable
        Throws:
        E - The first throwable caught when executing the push methods, if any. Any throwable caught after the first will have been suppressed.
        E extends Exception