CloseableScope
CloseableScope is a tiny Java library that implements single interface CloseableScope
, which is an unchecked version of
AutoCloseable
.
Download
Get CloseableScope from Maven Central:
<dependency> <groupId>com.machinezoo.closeablescope</groupId> <artifactId>closeablescope</artifactId> <version>1.0.1</version> </dependency>
Or clone sources from GitHub or Bitbucket. Don't forget to configure your build for Java 11+. Sources and binaries are distributed under Apache License 2.0.
If your project is a Java module,
add the following declaration to your module-info.java
:
requires com.machinezoo.closeablescope;
Usage
CloseableScope
is intended for creating custom scoping rules that ensure some code runs at the end of the scope, for example:
static CloseableScope test() { System.out.println("Open scope."); return () -> System.out.println("Close scope."); } static void main(String args[]) { try (var scope = test()) { System.out.println("Run in scope."); } }
This produces the following output:
Open scope. Run in scope. Close scope.
Closing code runs even if exception is thrown in the try-with-resources block. The above code is equivalent to try-finally block:
System.out.println("Open scope."); try { System.out.println("Run in scope."); } finally { System.out.println("Close scope."); }
Nesting
You can of course nest try-with-resources blocks, but sometimes inner scope must be automatically opened together with outer scope,
for example when the outer scope extends functionality of the inner scope.
CloseableScope
offers method andFinally(Runnable)
for this purpose.
static CloseableScope inner() { System.out.println("Open inner."); return () -> System.out.println("Close inner."); } static CloseableScope outer() { System.out.println("Open outer."); var inner = inner(); return inner.andFinally(() -> System.out.println("Close outer.")); } static void main(String args[]) { try (var scope = outer()) { System.out.println("Run in scope."); } }
This produces the following output:
Open outer. Open inner. Run in scope. Close inner. Close outer.
Outer closing code will run even if the inner closing code throws.
There's also andThen(Runnable)
method,
which differs in this detail.
Alternatives
There are a few alternatives to this library, each with its tradeoffs:
- The most common alternative is to create concrete implementation of
AutoCloseable
and drop exception specification from itsclose()
method. The downside is that you now have an extra type in your API. - You could return
AutoCloseable
directly, but then the calling code would have to handle checked exceptions. - A wholly different approach is to take lambda parameter instead of returning
CloseableScope
. This spares you of the scope variable and it simplifies nesting, but it comes with all the downsides of lambdas and you will likely need two versions of every scoping method, one forRunnable
and one forSupplier
. - You can easily reimplement
CloseableScope
yourself, but it's more convenient to use a library. If you want to reimplement it, feel free to take inspiration from its source code.