Field note / Java Caching

Speeding Up Java Applications with Caffeine: A Comprehensive Guide

A comprehensive guide to using Caffeine cache for high-performance caching in Java applications.

2 min read

  • Java Caching
  • Caffeine Cache
  • Performance Optimization
  • Spring Boot

Caching is like coffee for your Java application—it keeps things running faster and smoother. And when it comes to caching libraries, Caffeine is the double espresso of the Java world. Built to replace Guava Cache, Caffeine is a high-performance, flexible caching solution with a Java-friendly API and thoughtful design choices.


What is Caffeine?

Caffeine is a Java caching library modeled after Google’s Guava Cache but optimized for higher performance. It employs efficient algorithms, supports asynchronous loading, and offers extensive configuration options.

Key Features:

  1. Flexible expiration policies (time-based, size-based, or custom).
  2. Write-ahead caching for expensive computations.
  3. Efficient eviction policies.
  4. Integration-friendly with frameworks like Spring.

Setting Up Caffeine

Maven:

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version>
</dependency>

Gradle:

implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'

Configuring a Cache

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

public class CaffeineExample {
    public static void main(String[] args) {
        Cache<String, String> cache = Caffeine.newBuilder()
                .initialCapacity(20)
                .maximumSize(200)
                .expireAfterAccess(Duration.ofHours(1))
                .expireAfterWrite(24, TimeUnit.HOURS)
                .build();

        cache.put("key1", "value1");
        String value = cache.getIfPresent("key1");
        System.out.println("Cached Value: " + value);
    }
}

Configuration Breakdown

  • initialCapacity(20): Pre-allocates space for 20 entries.
  • maximumSize(200): Limits the cache to 200 entries with LRU eviction.
  • expireAfterAccess(1 hour): Removes entries not accessed in the last hour.
  • expireAfterWrite(24 hours): Removes entries 24 hours after creation.

Real-World Use Case: API Response Caching

public class WeatherCache {
    private final Cache<String, String> cache = Caffeine.newBuilder()
            .maximumSize(100)
            .expireAfterWrite(1, TimeUnit.HOURS)
            .build();

    public String getWeather(String city) {
        return cache.get(city, this::fetchWeatherFromApi);
    }

    private String fetchWeatherFromApi(String city) {
        System.out.println("Fetching weather for: " + city);
        return "Sunny in " + city;
    }

    public static void main(String[] args) {
        WeatherCache weatherCache = new WeatherCache();
        System.out.println(weatherCache.getWeather("Miami"));
        System.out.println(weatherCache.getWeather("Miami")); // Cached!
    }
}

Best Practices

  1. Understand your eviction policies: Don’t combine size-based and time-based policies unnecessarily.
  2. Monitor your cache: Use cache.stats().hitRate() for hit/miss ratios.
  3. Choose the right cache size: Start small and profile before scaling up.
  4. Use async APIs for expensive computations.

Final Thoughts

Caffeine is a powerful, easy-to-use caching library that fits seamlessly into modern Java applications. With its robust configuration options, you can fine-tune cache behavior to your application’s needs, whether it’s minimizing database load, improving response times, or handling expensive computations.

← All writing