Introdução ao cache em Kotlin
Aplicativos modernos em Kotlin, sejam soluções backend no servidor ou clientes Android, frequentemente enfrentam problemas de desempenho ao trabalhar com dados. Consultas repetitivas a bancos de dados, APIs externas ou cálculos pesados podem desacelerar significativamente o sistema. O cache é uma maneira eficaz de reduzir a carga e acelerar as respostas do aplicativo. Neste artigo, veremos três abordagens principais para cache no ecossistema Kotlin: uso de Redis, Memcached e soluções in-memory integradas. Você aprenderá como escolher a ferramenta adequada e implementá-la em seu projeto.
O que é cache e por que ele é necessário em Kotlin?
Cache é o processo de armazenar dados frequentemente solicitados em um armazenamento temporário de acesso rápido. Em vez de executar uma operação cara toda vez (consulta ao banco de dados, acesso à rede), o aplicativo primeiro verifica o cache. Se os dados estiverem lá (cache hit), eles são retornados instantaneamente. Se não estiverem (cache miss), a operação principal é executada e o resultado é salvo no cache para consultas futuras.
Principais vantagens do cache em Kotlin:
- Redução do tempo de resposta — os dados do cache são retornados em milissegundos.
- Diminuição da carga no banco de dados e serviços externos.
- Economia de recursos — menos operações de CPU e rede.
- Escalabilidade — caches distribuídos (Redis, Memcached) escalam facilmente.
Em Kotlin, graças à sua compatibilidade com Java e às poderosas coroutines, o cache é implementado de forma especialmente elegante.
Soluções integradas para cache em Kotlin
Para projetos pequenos ou cache local dentro de um único processo JVM, você pode usar ferramentas integradas. Elas não exigem instalação de serviços externos e são ideais para prototipagem.
Cache in-memory simples com ConcurrentHashMap
A maneira mais simples é usar ConcurrentHashMap com suporte a TTL (tempo de vida). Aqui está um exemplo de implementação:
import java.util.concurrent.ConcurrentHashMapimport java.util.concurrent.TimeUnit
class SimpleCache<K, V>(private val ttlMillis: Long) { private val cache = ConcurrentHashMap<K, CacheEntry<V>>()
private data class CacheEntry<V>(val value: V, val expiryTime: Long)
fun put(key: K, value: V) { val expiryTime = System.currentTimeMillis() + ttlMillis cache[key] = CacheEntry(value, expiryTime) }
fun get(key: K): V? { val entry = cache[key] ?: return null if (System.currentTimeMillis() > entry.expiryTime) { cache.remove(key) return null } return entry.value }
fun invalidate(key: K) { cache.remove(key) }
fun clear() { cache.clear() }}
// Usofun main() { val cache = SimpleCache<String, String>(TimeUnit.MINUTES.toMillis(5)) cache.put("user_42", "{\\"name\\":\\"Alice\\"}") val user = cache.get("user_42") println(user) // Exibe a string JSON}Essa abordagem é simples, mas não é adequada para sistemas distribuídos.
Uso do Caffeine — biblioteca avançada
Para cenários mais complexos, recomenda-se a biblioteca Caffeine. Ela fornece um cache de alto desempenho com descarregamento automático, estatísticas e carregamento assíncrono. Adicione a dependência no build.gradle.kts:
implementation("com.github.ben-manes.caffeine:caffeine:3.1.8")Exemplo de uso do Caffeine com coroutines:
import com.github.benmanes.caffeine.cache.Caffeineimport kotlinx.coroutines.runBlockingimport java.util.concurrent.TimeUnit
data class Product(val id: Int, val name: String, val price: Double)
class ProductService { private val ca
```