Java
Ehcache
Caching
Data Structures
Integer List

Ehcache - using a ListInteger as the cache value

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Using a List<Integer> as an Ehcache value is perfectly valid, but there are two practical concerns: Java’s generic type erasure and value mutability. Ehcache can cache a list just fine, but your code still needs to choose the cache type carefully and decide whether callers are allowed to mutate the cached list after retrieval.

Declare the Cache With the Right Value Type

In Ehcache 3, the cache is declared with a key type and a value type. Because Java erases generic parameters at runtime, the runtime type is still List.class even though the application code treats the value as List<Integer>.

java
1import java.util.List;
2import org.ehcache.Cache;
3import org.ehcache.CacheManager;
4import org.ehcache.config.builders.CacheConfigurationBuilder;
5import org.ehcache.config.builders.CacheManagerBuilder;
6import org.ehcache.config.builders.ResourcePoolsBuilder;
7
8public class IntegerListCacheExample {
9    public static void main(String[] args) {
10        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
11            .withCache(
12                "numbers",
13                CacheConfigurationBuilder.newCacheConfigurationBuilder(
14                    String.class,
15                    (Class<List<Integer>>) (Class<?>) List.class,
16                    ResourcePoolsBuilder.heap(100)
17                )
18            )
19            .build(true);
20
21        Cache<String, List<Integer>> cache = cacheManager.getCache(
22            "numbers",
23            String.class,
24            (Class<List<Integer>>) (Class<?>) List.class
25        );
26
27        cache.put("primes", List.of(2, 3, 5, 7));
28        System.out.println(cache.get("primes"));
29
30        cacheManager.close();
31    }
32}

The cast is awkward, but it is a normal consequence of type erasure. At compile time your code is List<Integer>. At runtime the cache sees List.

Prefer Immutable Lists for Cached Values

A cache works best when values behave like snapshots. If a caller reads a list from the cache and then mutates it, other parts of the application may observe those changes unexpectedly.

java
1import java.util.ArrayList;
2import java.util.List;
3
4public class ScoreService {
5    private final Cache<String, List<Integer>> cache;
6
7    public ScoreService(Cache<String, List<Integer>> cache) {
8        this.cache = cache;
9    }
10
11    public List<Integer> getScores() {
12        List<Integer> cached = cache.get("scores");
13        if (cached != null) {
14            return cached;
15        }
16
17        List<Integer> loaded = new ArrayList<>();
18        loaded.add(10);
19        loaded.add(20);
20        loaded.add(30);
21
22        List<Integer> safeCopy = List.copyOf(loaded);
23        cache.put("scores", safeCopy);
24        return safeCopy;
25    }
26}

List.copyOf makes the intent clear: the cached value should be read, not edited in place.

Think About Serialization Early

If the cache is heap-only, Ehcache stores normal Java objects in memory. If you later add off-heap or disk tiers, the values may need to be serialized. Integer is already serializable, so the main concern is whether the concrete list implementation is safe for that tier.

java
1CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
2    .withCache(
3        "numbers",
4        CacheConfigurationBuilder.newCacheConfigurationBuilder(
5            String.class,
6            (Class<List<Integer>>) (Class<?>) List.class,
7            ResourcePoolsBuilder.heap(50).offheap(10, org.ehcache.config.units.MemoryUnit.MB)
8        )
9    )
10    .build(true);

A cache that works on heap can still fail later if you switch to off-heap or disk without checking how the values are serialized.

Update Cached Lists by Replacing the Whole Value

Treat the list as a value object. Read the current list, build a new list with the update, and write the new list back.

java
1import java.util.ArrayList;
2import java.util.List;
3
4public static void appendValue(Cache<String, List<Integer>> cache, String key, int next) {
5    List<Integer> current = cache.get(key);
6    List<Integer> updated = new ArrayList<>();
7
8    if (current != null) {
9        updated.addAll(current);
10    }
11
12    updated.add(next);
13    cache.put(key, List.copyOf(updated));
14}

This is easier to reason about than mutating a list instance that may already be shared in memory or serialized in another tier.

Common Pitfalls

  • Assuming List<Integer> is special when the runtime cache type is still just List.class.
  • Storing a mutable list and then modifying it after putting it into the cache.
  • Forgetting that off-heap or disk tiers can introduce serialization requirements.
  • Using null as a meaningful cached value when an empty immutable list would be clearer.
  • Caching tiny, cheap-to-compute lists that do not really benefit from a cache at all.

Summary

  • Ehcache can store a List<Integer> value without any unusual trick beyond the normal List.class runtime cast.
  • Prefer immutable lists so cached values behave like snapshots.
  • Test serialization behavior if you use off-heap or disk tiers.
  • Replace cached lists wholesale instead of mutating them in place.
  • Cache collections only when they are actually expensive or frequently reused.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.