In this article, we will find how we can implement a simple data holder class in Java.
The purpose of this class is to store an object instance, provided by a supplier, until is invalidated. Once invalidation happens, supplier will be called again to provide a new object instance that we are going to hold internally. Invalidation will work in a lazy mode, will just mark data object as dirty and next time when the object will be requested, the supplier will have to be called.
Class description:
- hold any object type:
T
- a single constructor which accepts a
Supplier<T>
as input - a method to retrieve current data object:
T get()
- a method to invalidate current data object:
void invalidate()
In addition, we need to take into account also thread safety. If get
method is called in the same time by two threads and object is marked as invalidated, we should avoid to call supplier twice.
A possible implementation looks like this:
import lombok.RequiredArgsConstructor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@RequiredArgsConstructor
public final class DataHolder<T> {
private final AtomicBoolean dirtyFlag = new AtomicBoolean(true);
private final Supplier<T> dataSupplier;
private T data;
public T get() {
if (dirtyFlag.compareAndSet(true, false)) {
data = dataSupplier.get();
}
return data;
}
public void invalidate() {
dirtyFlag.set(true);
}
}
Implementation details:
- use power of Java 8 to define a
Supplier
. - use power of generics to hold any type of data:
T
- use a dirty flag to mark data object as invalidated.
AtomicBoolean
type is perfect in our case. - invalidate method is just setting the flag to
true
get
method will first check if dirty flag is set (and if so, it will set tofalse
in an atomic mode) and will refresh object data, by calling again the supplier.
We can use this data holder class, when we have to cache an object which is quite expensive to be obtained each time and of course, when is not changed too often.