public interface Cleanup
registerCleanup(Consumer, Object)
must be run at the end of or after construction (code
run after that could invalidate the object, which could lead to problems). The configured
cleanup action is run when this does not exist anymore. Therefore the
value must not contain any references to this.
You can use addExceptionHandler(Consumer)
to handle exceptions (e.g. send exceptions to
your logging system).
Pros and Cons and Pitfalls:
|
|
* Cleanup actions are always only run for discarded objects. You should use
Runtime.addShutdownHook(Thread)
for all code that must run on shutdown.
A note from the author:
I decided to use the name Cleanup because it is simple to understand. However, there is
the try-with-resource statement which is much better if you actually need to close something.
Cleanup should be used for code that isn't critical, such as logging and debugging.
I recommend using static methods instead of lambdas:
foo.registerCleanup(Foo::cleanup);
This is shown in the Example, which you can find in the test-folder. It is very safe and easy to
understand for others, as you can include the static method in your API documentation.
Modifier and Type | Method and Description |
---|---|
static void |
addExceptionHandler(Consumer<Throwable> handler)
Adds a handler for Exceptions thrown during cleanup.
|
default void |
registerAutoClose(AutoCloseable... resources)
Easy registration of
auto-closeable resources. |
static void |
registerAutoClose(Object object,
AutoCloseable... resources)
Register any object and its resources for cleanup.
|
default <V> void |
registerCleanup(Consumer<V> cleanup,
V value)
Register method to clean up after garbage collection removed this.
|
static <V> void |
registerCleanup(Object object,
Consumer<V> cleanup,
V value)
Register any object and a value for cleanup.
|
default void |
registerCleanup(Runnable cleanup)
Convenience method for cleanup actions that does not need any value.
|
static void |
runCleanup()
Runs the pending cleanup actions.
|
static void |
runCleanupOnExit(boolean value)
Runs cleanup code by the use of
Runtime.addShutdownHook(Thread) . |
static void |
setCleanupPriority(int newPriority)
Changes the priority of the cleanup thread.
|
static void addExceptionHandler(Consumer<Throwable> handler)
It is recommended that you use this for logging, to be able to find problems in the cleanup actions.
handler
- a handler for all cleanup exceptions.default <V> void registerCleanup(Consumer<V> cleanup, V value)
The value is any data structure that holds everything you need for the cleanup.
Examples: Database connection to be closed. Stream to be closed. ID to be logged. etc.
But it must not hold any references to this. Note that instances of inner / anonymous
classes also hold implicit references to the outer instance. However, you can reference fields
directly in the lambda, instead of using value, as long as the objects do not reference
this.
Multiple actions can be registered and each time a new PhantomReference
will be
created.
Cleanup is synchronized on it's value, but multiple cleanup actions use different
values. So you might want to use some Lock
to ensure visibility.
V
- generic type of the valuecleanup
- A consumer that defines the cleanup actionvalue
- All data needed for cleanup, or nullIllegalArgumentException
- thrown if value is obviously holding a reference to thisdefault void registerCleanup(Runnable cleanup)
Make sure you do not capture a reference to this in your expression. However, you may capture other values, like objects from local, effectively final variables.
This is especially useful for static cleanup actions:
foo.registerCleanup(Foo::cleanup);
All you need is a static, void, no-args method in your class:
class Foo {
public static void cleanup() { ... }
}
cleanup
- runnable cleanup actionregisterCleanup(Consumer, Object)
default void registerAutoClose(AutoCloseable... resources)
auto-closeable
resources.
The resources are closed as they are listed, from first to last. Therefore you should list them in the opposite order of their creation.
The documentation of AutoCloseable.close()
states that it is not required to be
idempotent. But for a cleanup action it is recommended to always use resources with an
idempotent close method (cf. Connection.close()
,
Closeable.close()
).
resources
- auto-closeable resources.NullPointerException
- if null is passed as a resourceIllegalArgumentException
- if this is passed as a resourcestatic <V> void registerCleanup(Object object, Consumer<V> cleanup, V value)
V
- generic type of the valueobject
- object for which a PhantomReference
will be createdcleanup
- A consumer to clean up the valuevalue
- All data needed for cleanup, or nullIllegalArgumentException
- thrown if value is obviously holding a reference to thisregisterCleanup(Consumer, Object)
static void registerAutoClose(Object object, AutoCloseable... resources)
non-static method
for more information.object
- object for which a PhantomReference
will be createdresources
- auto-closeable resources.NullPointerException
- if null is passed as the object or a resourceIllegalArgumentException
- if any resource is the objectregisterAutoClose(AutoCloseable...)
static void runCleanupOnExit(boolean value)
Runtime.addShutdownHook(Thread)
. This is an alternative
to the deprecated Runtime.runFinalizersOnExit(boolean)
. But note that only cleanup
actions of discarded objects are run. For objects that live until shutdown the action needs to
be registered by Runtime.addShutdownHook(Thread)
additionally. Such an action will run
when the object might still be in use by any threads. Cleanup actions, on the other hand, are
designed to run for discarded objects only.value
- true to enable cleanup on exit, false to disableThread.setDaemon(boolean)
static void setCleanupPriority(int newPriority)
Thread.MIN_PRIORITY
.newPriority
- priority to set thread toIllegalArgumentException
- If the priority is not in the range MIN_PRIORITY to MAX_PRIORITY.SecurityException
- if the current thread cannot modify the cleanup thread.Thread.setPriority(int)
,
Thread.MAX_PRIORITY
,
Thread.MIN_PRIORITY
static void runCleanup()
Cleanup actions are processed automatically as needed, if the runCleanup method is not invoked explicitly.
This does not invoke System.gc();
and therefore only blocks until all objects are
handled that were already discarded.
Runtime.runFinalization()