Cache4k

Cache LibraryKotlinLRUMemory CacheCoroutinesMultiplatform

Cache Library

Cache4k

Overview

Cache4k is a lightweight and high-performance in-memory cache library designed specifically for Kotlin Native and Kotlin Multiplatform projects.

Details

Cache4k is a memory caching library specifically designed for the Kotlin ecosystem, supporting LRU (Least Recently Used) eviction policy. The library has no external dependencies and is written entirely in Kotlin, making it compatible with all Kotlin platforms including Kotlin/JVM, Kotlin/JS, and Kotlin/Native. Its coroutine-compatible asynchronous API design allows seamless integration with modern Kotlin applications. The type-safe API ensures compile-time type safety, reducing runtime errors. Despite its simple API, it provides customizable configuration options to accommodate various use cases. Its lightweight design enables efficient operation even in resource-constrained environments, making it suitable for Android development and server-side Kotlin applications.

Advantages and Disadvantages

Advantages

  • Kotlin-Specific Design: Natural API design leveraging Kotlin language features
  • Multiplatform Support: Works on Kotlin/JVM, Kotlin/JS, and Kotlin/Native
  • Lightweight: No external dependencies, minimizing application bundle size
  • Coroutine Support: High compatibility with asynchronous processing
  • Type Safety: Compile-time type checking reduces errors
  • High Performance: Efficient memory management with LRU algorithm
  • Simple API: Low learning curve with intuitive operations

Disadvantages

  • Kotlin Only: Cannot be used from other languages
  • Memory Cache Only: No persistence functionality
  • Limited Features: Advanced cache features (distribution, replication, etc.) not supported
  • Ecosystem: Still relatively new with limited track record
  • Documentation: Less documentation compared to larger libraries

Key Links

Code Examples

Basic Cache Usage

import io.github.reactivecircus.cache4k.Cache

// Create cache instance
val cache = Cache.Builder<String, String>()
    .maximumCacheSize(100)
    .build()

// Store data
cache.put("key1", "value1")

// Retrieve data
val value = cache.get("key1")
println(value) // "value1"

Setting Expiration Time

import kotlin.time.Duration.Companion.minutes

// Cache with expiration
val cache = Cache.Builder<String, String>()
    .maximumCacheSize(100)
    .expireAfterWrite(10.minutes)
    .build()

// Store data (automatically deleted after 10 minutes)
cache.put("session", "user123")

// Check expiration
if (cache.get("session") != null) {
    println("Session is valid")
}

Using Custom Loader

// Auto-load on cache miss
val cache = Cache.Builder<String, String>()
    .maximumCacheSize(50)
    .build()

// Auto-load using getOrPut
val value = cache.getOrPut("user:123") {
    // Database fetch logic
    fetchUserFromDatabase("123")
}

Asynchronous Usage with Coroutines

import kotlinx.coroutines.runBlocking

suspend fun fetchDataAsync(key: String): String {
    // Asynchronous data fetch logic
    return "async_data_for_$key"
}

runBlocking {
    val cache = Cache.Builder<String, String>()
        .maximumCacheSize(100)
        .build()
    
    // Asynchronous cache operations
    val result = cache.getOrPut("async_key") {
        fetchDataAsync("async_key")
    }
    
    println(result) // "async_data_for_async_key"
}

Cache Statistics

// Enable statistics
val cache = Cache.Builder<String, String>()
    .maximumCacheSize(100)
    .recordStats()
    .build()

// Data operations
cache.put("key1", "value1")
cache.get("key1")
cache.get("key2") // Cache miss

// Get statistics
val stats = cache.stats()
println("Hit rate: ${stats.hitRate}")
println("Miss count: ${stats.missCount}")
println("Eviction count: ${stats.evictionCount}")

Android Practical Example

class UserRepository(
    private val apiService: ApiService
) {
    // User info cache (5 minutes)
    private val userCache = Cache.Builder<String, User>()
        .maximumCacheSize(100)
        .expireAfterWrite(5.minutes)
        .build()
    
    suspend fun getUser(userId: String): User {
        return userCache.getOrPut(userId) {
            apiService.fetchUser(userId)
        }
    }
    
    fun clearUserCache() {
        userCache.invalidateAll()
    }
}