A high performance caching library for Java providing Google Guava-inspired API with advanced eviction policies and comprehensive features
—
The Caffeine builder provides a comprehensive fluent API for configuring cache instances. The builder pattern allows combining multiple configuration options and terminates with methods that create the actual cache instances.
public static Caffeine<Object, Object> newBuilder()
public static Caffeine<Object, Object> from(CaffeineSpec spec)
public static Caffeine<Object, Object> from(String spec)// Basic builder creation
Caffeine<Object, Object> builder = Caffeine.newBuilder();
// From specification string
Caffeine<Object, Object> builder2 = Caffeine.from("maximumSize=10000,expireAfterWrite=10m");
// From specification object
CaffeineSpec spec = CaffeineSpec.parse("maximumSize=10000,expireAfterWrite=10m");
Caffeine<Object, Object> builder3 = Caffeine.from(spec);Configure cache capacity using either entry count or custom weights.
public Caffeine<K, V> initialCapacity(int initialCapacity)
public Caffeine<K, V> maximumSize(long maximumSize)
public Caffeine<K, V> maximumWeight(long maximumWeight)
public <K1, V1> Caffeine<K1, V1> weigher(Weigher<? super K1, ? super V1> weigher)// Size-based eviction
Cache<String, String> sizeCache = Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(10_000)
.build();
// Weight-based eviction with custom weigher
Cache<String, String> weightCache = Caffeine.newBuilder()
.maximumWeight(100_000)
.weigher((key, value) -> key.length() + value.length())
.build();Constraints: Cannot use both maximumSize() and maximumWeight() on the same builder.
Configure memory management behavior for keys and values.
public Caffeine<K, V> weakKeys()
public Caffeine<K, V> weakValues()
public Caffeine<K, V> softValues()// Weak references for keys (allows GC when no other references exist)
Cache<String, String> weakKeyCache = Caffeine.newBuilder()
.maximumSize(1000)
.weakKeys()
.build();
// Soft references for values (GC under memory pressure)
Cache<String, LargeObject> softValueCache = Caffeine.newBuilder()
.maximumSize(1000)
.softValues()
.build();Constraints:
Configure time-based entry expiration using fixed or variable policies.
// Fixed expiration policies
public Caffeine<K, V> expireAfterWrite(Duration duration)
public Caffeine<K, V> expireAfterWrite(long duration, TimeUnit unit)
public Caffeine<K, V> expireAfterAccess(Duration duration)
public Caffeine<K, V> expireAfterAccess(long duration, TimeUnit unit)
// Variable expiration policy
public <K1, V1> Caffeine<K1, V1> expireAfter(Expiry<? super K1, ? super V1> expiry)// Fixed expiration after write
Cache<String, String> writeExpireCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(Duration.ofMinutes(10))
.build();
// Fixed expiration after access
Cache<String, String> accessExpireCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterAccess(30, TimeUnit.MINUTES)
.build();
// Variable expiration based on entry characteristics
Cache<String, String> variableExpireCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfter(Expiry.creating((key, value) ->
key.startsWith("temp_") ? Duration.ofMinutes(5) : Duration.ofHours(1)))
.build();Constraints: Cannot mix expireAfter(Expiry) with other expiration methods.
Configure automatic background refresh for loading caches.
public Caffeine<K, V> refreshAfterWrite(Duration duration)
public Caffeine<K, V> refreshAfterWrite(long duration, TimeUnit unit)LoadingCache<String, String> refreshingCache = Caffeine.newBuilder()
.maximumSize(1000)
.refreshAfterWrite(Duration.ofMinutes(5))
.build(key -> fetchFromDatabase(key));
// Old value remains available during refresh
String value = refreshingCache.get("key"); // Returns cached value while refreshingConstraints: Only applicable to LoadingCache and AsyncLoadingCache instances.
Configure threading and scheduling for cache operations.
public Caffeine<K, V> executor(Executor executor)
public Caffeine<K, V> scheduler(Scheduler scheduler)
public Caffeine<K, V> ticker(Ticker ticker)// Custom executor for async operations
ExecutorService customExecutor = Executors.newFixedThreadPool(4);
Cache<String, String> customExecCache = Caffeine.newBuilder()
.executor(customExecutor)
.maximumSize(1000)
.build();
// Custom scheduler for maintenance
ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(1);
Cache<String, String> customSchedCache = Caffeine.newBuilder()
.scheduler(Scheduler.forScheduledExecutorService(scheduledExecutor))
.expireAfterWrite(Duration.ofMinutes(10))
.maximumSize(1000)
.build();
// Custom ticker for testing
Cache<String, String> testCache = Caffeine.newBuilder()
.ticker(Ticker.disabledTicker()) // Always returns 0
.expireAfterWrite(Duration.ofMinutes(10))
.maximumSize(1000)
.build();Configure callbacks for cache entry removal events.
public <K1, V1> Caffeine<K1, V1> evictionListener(RemovalListener<? super K1, ? super V1> evictionListener)
public <K1, V1> Caffeine<K1, V1> removalListener(RemovalListener<? super K1, ? super V1> removalListener)// Eviction listener (called during cache operations)
Cache<String, String> evictionListenerCache = Caffeine.newBuilder()
.maximumSize(1000)
.evictionListener((key, value, cause) -> {
if (cause.wasEvicted()) {
System.out.println("Evicted: " + key + " -> " + value + " (" + cause + ")");
}
})
.build();
// Removal listener (called asynchronously)
Cache<String, String> removalListenerCache = Caffeine.newBuilder()
.maximumSize(1000)
.removalListener((key, value, cause) -> {
System.out.println("Removed: " + key + " -> " + value + " (" + cause + ")");
// Cleanup resources, log to external system, etc.
})
.build();Difference:
evictionListener: Called synchronously during cache operationsremovalListener: Called asynchronously for all removal eventsEnable cache performance tracking and statistics collection.
public Caffeine<K, V> recordStats()
public Caffeine<K, V> recordStats(Supplier<? extends StatsCounter> statsCounterSupplier)// Basic statistics recording
Cache<String, String> statsCache = Caffeine.newBuilder()
.maximumSize(1000)
.recordStats()
.build();
CacheStats stats = statsCache.stats();
System.out.println("Hit rate: " + stats.hitRate());
// Custom statistics counter
Cache<String, String> customStatsCache = Caffeine.newBuilder()
.maximumSize(1000)
.recordStats(ConcurrentStatsCounter::new)
.build();Create the actual cache instances from the configured builder.
// Synchronous cache creation
public <K1 extends K, V1 extends V> Cache<K1, V1> build()
public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(CacheLoader<? super K1, V1> loader)
// Asynchronous cache creation
public <K1 extends K, V1 extends V> AsyncCache<K1, V1> buildAsync()
public <K1 extends K, V1 extends V> AsyncLoadingCache<K1, V1> buildAsync(CacheLoader<? super K1, V1> loader)
public <K1 extends K, V1 extends V> AsyncLoadingCache<K1, V1> buildAsync(AsyncCacheLoader<? super K1, V1> loader)// Manual cache
Cache<String, String> manualCache = Caffeine.newBuilder()
.maximumSize(1000)
.build();
// Loading cache with CacheLoader
LoadingCache<String, String> loadingCache = Caffeine.newBuilder()
.maximumSize(1000)
.build(key -> "loaded_" + key);
// Async cache
AsyncCache<String, String> asyncCache = Caffeine.newBuilder()
.maximumSize(1000)
.buildAsync();
// Async loading cache with CacheLoader
AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
.maximumSize(1000)
.buildAsync(key -> "async_loaded_" + key);
// Async loading cache with AsyncCacheLoader
AsyncLoadingCache<String, String> asyncLoaderCache = Caffeine.newBuilder()
.maximumSize(1000)
.buildAsync((key, executor) -> CompletableFuture.supplyAsync(() -> "async_" + key, executor));The builder performs runtime validation to prevent incompatible configuration combinations:
maximumSize() and maximumWeight()expireAfter(Expiry) with fixed expiration methodsrefreshAfterWrite() only works with loading cache typesAttempting incompatible combinations will throw IllegalStateException during cache creation.
Install with Tessl CLI
npx tessl i tessl/maven-com-github-ben-manes-caffeine--caffeine