SimpleCache.java
package space.sunqian.fs.cache;
import space.sunqian.annotation.Nonnull;
import space.sunqian.annotation.Nullable;
import space.sunqian.annotation.ThreadSafe;
import space.sunqian.fs.base.value.Val;
import java.lang.ref.PhantomReference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* This interface is a simplified key-value pair cache interface (implementations must be thread-safe). It only provides
* get, put, remove and clean operations, and supports null value but does not allow null key. It is suitable for
* scenarios that require simple cache operations and do not care about the cache lifecycle.
* <p>
* It is recommended to use the skeletal implementation: {@link AbstractSimpleCache}.
*
* @param <K> the key type
* @param <V> the value type
* @author sunqian
* @implNote Although the default implementations will call {@link #clean()} every time they execute other methods, it
* is recommended to take some measures to enable the {@link #clean()} to call regularly to clean invalid entries
* @see AbstractSimpleCache
*/
@ThreadSafe
public interface SimpleCache<K, V> extends CacheFunction<K, V> {
/**
* Returns a new {@link SimpleCache} based on {@link WeakReference} and {@link ConcurrentHashMap}. The values of the
* returned cache will be automatically collected by the garbage collection based on the characteristics of
* {@link WeakReference}. Its {@link #clean()} method releases all entries of which values are collected, and this
* method is automatically invoked once every time another method is executed.
*
* @param <K> the key type
* @param <V> the value type
* @return a new {@link SimpleCache} based on {@link WeakReference}
*/
static <K, V> @Nonnull SimpleCache<K, V> ofWeak() {
return SimpleCacheBack.ofWeak();
}
/**
* Returns a new {@link SimpleCache} based on {@link SoftReference} and {@link ConcurrentHashMap}. The values of the
* returned cache will be automatically collected by the garbage collection based on the characteristics of
* {@link SoftReference}. Its {@link #clean()} method releases all entries of which values are collected, and this
* method is automatically invoked once every time another method is executed.
*
* @param <K> the key type
* @param <V> the value type
* @return a new {@link SimpleCache} based on {@link SoftReference}
*/
static <K, V> @Nonnull SimpleCache<K, V> ofSoft() {
return SimpleCacheBack.ofSoft();
}
/**
* Returns a new {@link SimpleCache} based on {@link PhantomReference} and {@link ConcurrentHashMap}. The values of
* the returned cache will be automatically collected by the garbage collection based on the characteristics of
* {@link PhantomReference}. Its {@link #clean()} method releases all entries of which values are collected, and
* this method is automatically invoked once every time another method is executed.
*
* @param <K> the key type
* @param <V> the value type
* @return a new {@link SimpleCache} based on {@link PhantomReference}
*/
static <K, V> @Nonnull SimpleCache<K, V> ofPhantom() {
return SimpleCacheBack.ofPhantom();
}
/**
* Returns a new {@link SimpleCache} based on strong reference and {@link ConcurrentHashMap}. The values of the
* returned cache will never automatically be invalid, and its {@link #clean()} method does nothing. The behavior of
* the returned cache is just like a regular {@link Map}.
*
* @param <K> the key type
* @param <V> the value type
* @return a new {@link SimpleCache} based on strong reference
*/
static <K, V> @Nonnull SimpleCache<K, V> ofStrong() {
return SimpleCacheBack.ofStrong();
}
/**
* Returns a new {@link SimpleCache} based on the given map.
* <p>
* Note the returned cache treats {@code null} values as absent, which will lead to certain results in processing
* {@code null} values. Therefore, putting {@code null} values are not encouraged for returned map cache.
*
* @param map the given map to cache the value
* @param <K> the type of the key
* @param <V> the type of the value
* @return a new {@link SimpleCache} based on the given map
*/
static <K, V> @Nonnull SimpleCache<K, V> ofMap(@Nonnull Map<K, V> map) {
return SimpleCacheBack.ofMap(map);
}
/**
* Returns the value for the specified key, or {@code null} if the value is invalid or is {@code null} itself. Use
* {@link #getVal(Object)} to distinguish between these cases.
*
* @param key the specified key
* @return the value for the specified key, or {@code null} if the value is invalid or is {@code null} itself
*/
@Nullable
V get(@Nonnull K key);
/**
* Returns the value wrapped by {@link Val} for the specified key, or {@code null} if the value is invalid.
*
* @param key the specified key
* @return the value wrapped by {@link Val} for the specified key, or {@code null} if the value is invalid
*/
@Nullable
Val<@Nullable V> getVal(@Nonnull K key);
/**
* Returns the value for the specified key. If the value is invalid, the loader will be called to generate a new
* value, and the new value will be cached and returned. If an exception is thrown during the generation, the
* exception will be thrown directly. This operation is atomic.
* <p>
* Any value, including {@code null}, generated by the loader will be cached. To more explicitly to deal with the
* value, especially the {@code null} value, try {@link #getVal(Object, Function)}.
*
* @param key the specified key
* @param loader the function to generate new value for the specified key
* @return the value for the specified key, including {@code null}
*/
@Override
V get(@Nonnull K key, @Nonnull Function<? super @Nonnull K, ? extends @Nullable V> loader);
/**
* Returns the value wrapped by {@link Val} for the specified key. If the value is invalid, the loader will be
* called to generate a new value wrapped by {@link Val}, and the new value will be cached and returned. If an
* exception is thrown during the generation, the exception will be thrown directly. This operation is atomic.
* <p>
* If the loader generates a {@code null}, no value will be cached, and this method will return null.
*
* @param key the specified key
* @param loader the function to generate new value wrapped by {@link Val} for the specified key
* @return the value wrapped by {@link Val} for the specified key, or {@code null} if the loader generates a
* {@code null}
*/
@Nullable
Val<@Nullable V> getVal(
@Nonnull K key,
@Nonnull Function<? super @Nonnull K, ? extends @Nullable Val<? extends @Nullable V>> loader
);
/**
* Puts the key mapping the value into this cache.
*
* @param key the key
* @param value the value
*/
void put(@Nonnull K key, @Nullable V value);
/**
* Removes the value mapped by the key from this cache.
*
* @param key the key
*/
void remove(@Nonnull K key);
/**
* Returns the current size of this cache.
*
* @return the current size of this cache
*/
int size();
/**
* Removes all entries from this cache.
*/
void clear();
/**
* Tries to release invalid entries from this cache.
*/
void clean();
/**
* Copies and returns all current entries in this cache. The result map is independent of the cache, so any changes
* to the cache, including status changes of this cache itself, are not reflected to the map, and vice versa.
*
* @return a {@link Map} contains the copy of the current entries in this cache
*/
@Nonnull
Map<K, V> copyEntries();
}