Skip to content
-
Connect with us & stay updated with our latest blogs Connect Now!
Obvio Blogs

Where Ideas Find Clarity

Obvio Blogs

Where Ideas Find Clarity

  • Home
  • About
  • Culture
  • Life Hacks
  • Privacy Policy
  • Smart Money
  • Tech & Gear
  • Home
  • About
  • Culture
  • Life Hacks
  • Privacy Policy
  • Smart Money
  • Tech & Gear
Close

Search

  • Facebook
  • Instagram
  • Linkedin
  • WhatsApp
Follow
How to Create a Cache Object in Java
Technology

How to Create a Cache Object in Java: A Practical Guide

By Mudassar Ali
September 9, 2026 11 Min Read
0

Caching is one of the most common techniques used to improve the performance of Java applications. Instead of repeatedly retrieving the same information from a database, API, or another expensive source, an application can temporarily store frequently used data and retrieve it more quickly when it is needed again.

If you are wondering how to create a cache object in Java, there are several approaches. A simple cache can be created using Java collections such as HashMap, while applications with multiple threads may use ConcurrentHashMap. For production systems, a dedicated caching library can provide features such as expiration, maximum cache size, and automatic eviction.

This guide explains how to create a cache object in Java, starting with a simple implementation and gradually moving toward more practical caching solutions. To understand the underlying concept in more detail, see our guide to Java object cache and how object caching works.

Quick Answer

The simplest way to create a cache object in Java is to use a map that stores a key and its associated value.

For example:

Map<String, Object> cache = new HashMap<>();

cache.put("user:101", user);

Object cachedUser = cache.get("user:101");

For a multithreaded application, ConcurrentHashMap is generally more appropriate than a basic HashMap.

A production application may also benefit from a dedicated caching library that supports features such as TTL, eviction, maximum size, and cache statistics.

What Is a Cache Object in Java?

A cache object is an object or data structure used to temporarily store information that an application expects to access repeatedly.

A typical caching flow looks like this:

Application
     |
     v
Check Cache
     |
  +--+--+
  |     |
 Hit   Miss
  |     |
  v     v
Return  Load Data
Object  from Source
        |
        v
      Cache

For example, an application may retrieve a customer record from a database.

The first request might require a database query:

Application → Database → Customer Object

The application can then store that object in the cache:

Application → Cache → Customer Object

When another request needs the same customer, the application can retrieve the object from the cache instead of performing the same database operation again.

How to Create a Cache Object in Java

There isn’t a single built-in Cache class that you must use for every Java application.

Instead, you can create caching functionality using different approaches depending on your requirements.

The simplest approach is a Java collection.

For example:

Map<String, String> cache = new HashMap<>();

Here:

  • String is the key type.
  • The second String is the value type.
  • cache is the object used to store cached values.

You can then add an entry:

cache.put("username:101", "John");

And retrieve it:

String username = cache.get("username:101");

This gives you the basic behavior of a cache.

However, a real-world cache normally needs more functionality than simply storing and retrieving values.

Creating a Simple Object Cache with HashMap

A HashMap can be used to create a basic cache for Java objects. You can refer to the Java HashMap documentation for the class’s available methods and behavior.

Suppose you have a User class:

public class User {

    private int id;
    private String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

You can create a cache:

Map<Integer, User> userCache = new HashMap<>();

Then store a user:

User user = new User(101, "John");

userCache.put(user.getId(), user);

To retrieve the object:

User cachedUser = userCache.get(101);

If the entry exists, cachedUser references the stored User object.

This is the basic idea behind Java cache objects.

Checking Whether an Object Is Already Cached

Before retrieving an object from a database or another source, the application can check the cache.

For example:

User user = userCache.get(101);

if (user == null) {
    user = loadUserFromDatabase(101);
    userCache.put(101, user);
}

The logic is straightforward:

  1. Look for the user in the cache.
  2. If the user exists, use the cached object.
  3. If the user doesn’t exist, retrieve it from the database.
  4. Store the newly retrieved object in the cache.
  5. Use the object.

This approach is commonly associated with the cache-aside pattern.

Complete Basic Cache Example

Here is a simple example:

import java.util.HashMap;
import java.util.Map;

public class SimpleCache {

    private final Map<Integer, User> cache = new HashMap<>();

    public User getUser(int id) {

        User user = cache.get(id);

        if (user == null) {
            user = loadUser(id);
            cache.put(id, user);
        }

        return user;
    }

    private User loadUser(int id) {
        return new User(id, "John");
    }
}

This example demonstrates the fundamental concept without introducing a third-party caching library.

However, it should not automatically be considered a complete production-ready cache.

Why HashMap Isn’t Always Enough

Although HashMap is convenient, it doesn’t provide many features expected from a production caching system.

For example, a basic HashMap doesn’t automatically provide:

  • Expiration
  • TTL
  • Maximum cache size
  • Automatic eviction
  • Cache statistics
  • Advanced concurrency behavior

There is also an important issue when multiple threads access the same cache.

If your application handles concurrent requests, multiple threads may try to read and modify the cache at the same time.

For this reason, applications with concurrent access often need a more appropriate data structure.

Creating a Cache with ConcurrentHashMap

Java provides ConcurrentHashMap for concurrent access to key-value data. The Java ConcurrentHashMap documentation provides additional details about its concurrent map behavior and methods.

A simple cache can be created like this:

import java.util.concurrent.ConcurrentHashMap;

ConcurrentHashMap<Integer, User> userCache =
        new ConcurrentHashMap<>();

You can store an object:

User user = new User(101, "John");

userCache.put(101, user);

And retrieve it:

User cachedUser = userCache.get(101);

This is more suitable for many multithreaded use cases than sharing a normal HashMap between multiple threads.

Using putIfAbsent()

ConcurrentHashMap also provides useful atomic operations.

For example:

userCache.putIfAbsent(101, user);

This adds the value only if the specified key isn’t already present.

This can be useful when several threads may attempt to populate the same cache.

However, ConcurrentHashMap is still a map rather than a complete caching framework. You may need additional logic for expiration, eviction, and other cache-management requirements.

Using computeIfAbsent()

Another useful method is computeIfAbsent().

For example:

User user = userCache.computeIfAbsent(
    101,
    id -> loadUserFromDatabase(id)
);

The idea is:

  • If the object is already cached, use it.
  • If it isn’t cached, calculate/load the value.
  • Store the resulting value.
  • Return the value.

This can make simple cache implementations considerably cleaner.

A complete example could look like:

import java.util.concurrent.ConcurrentHashMap;

public class UserCache {

    private final ConcurrentHashMap<Integer, User> cache =
            new ConcurrentHashMap<>();

    public User getUser(int id) {
        return cache.computeIfAbsent(
            id,
            this::loadUserFromDatabase
        );
    }

    private User loadUserFromDatabase(int id) {
        return new User(id, "John");
    }
}

This is a useful approach for relatively simple in-memory caching.

Adding Expiration to a Java Cache

One of the biggest limitations of a basic map-based cache is that entries can remain in memory indefinitely. Java’s Java Duration API can be used to represent time-based amounts such as minutes and seconds.

Consider:

cache.put(101, user);

If nothing removes this object, it may remain associated with the cache for as long as the cache itself remains active.

For a small example this might not matter.

For a large application, however, continuously adding objects can cause unnecessary memory consumption.

A practical cache often needs expiration.

One way to implement expiration manually is to store the value together with its creation time.

For example:

class CacheEntry<T> {

    private final T value;
    private final long expirationTime;

    public CacheEntry(T value, long ttl) {
        this.value = value;
        this.expirationTime =
                System.currentTimeMillis() + ttl;
    }

    public boolean isExpired() {
        return System.currentTimeMillis() > expirationTime;
    }

    public T getValue() {
        return value;
    }
}

You could then store the entry:

Map<Integer, CacheEntry<User>> cache = new HashMap<>();

And create an entry with a TTL:

cache.put(
    101,
    new CacheEntry<>(user, 60_000)
);

The 60_000 value represents 60 seconds.

When retrieving the object, the application can check whether the entry has expired.

CacheEntry<User> entry = cache.get(101);

if (entry != null && !entry.isExpired()) {
    return entry.getValue();
}

return null;

This demonstrates how expiration works conceptually.

However, manually implementing every caching feature can quickly make the code complicated.

Using a Dedicated Caching Library

For production applications, developers often use a dedicated caching library instead of implementing expiration and eviction from scratch.

A caching library can provide features such as:

  • Maximum cache size
  • Expiration after access
  • Expiration after writing
  • Automatic eviction
  • Cache statistics
  • Concurrent access
  • Efficient memory management

One popular approach for local Java caching is the Caffeine Java caching library.

A Caffeine-based cache can be configured with limits and expiration rules.

For example:

Cache<Integer, User> cache = Caffeine.newBuilder()
        .maximumSize(10_000)
        .expireAfterWrite(Duration.ofMinutes(10))
        .build();

The application can then store an object:

cache.put(101, user);

And retrieve it:

User cachedUser = cache.getIfPresent(101);

This approach is much closer to what you might expect from a production-oriented local cache.

Loading Objects Automatically

A cache can also be configured to load an object when it doesn’t already exist.

Conceptually, the application wants this behavior:

Request object
      |
      v
Is object cached?
   /       \
 Yes        No
 |          |
Return      Load object
           |
           v
         Cache
           |
           v
         Return

Instead of writing the same lookup logic throughout the application, a loading cache can centralize this behavior.

For example:

LoadingCache<Integer, User> cache =
        Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(Duration.ofMinutes(10))
                .build(this::loadUser);

Then:

User user = cache.get(101);

If the value isn’t already cached, the configured loader can retrieve it.

This can make application code easier to maintain.

How Long Should a Java Cache Keep Objects?

There is no universal TTL that works for every application.

The appropriate expiration period depends on how frequently the underlying data changes.

For example:

Data TypePossible Caching Approach
Static configurationLong expiration
Product catalogMinutes to hours
User profileMinutes
Frequently changing pricesVery short TTL
Temporary computationApplication-dependent
Session-related dataBased on session requirements

The important principle is to choose expiration based on data freshness requirements, not simply because a particular TTL is common.

If stale data can cause serious problems, you may need a shorter TTL or explicit invalidation.

Cache Invalidation

Expiration is only one way to remove outdated objects.

Another approach is cache invalidation.

Suppose a user’s name is changed in the database:

Database:
John → Jonathan

But the cache still contains:

Cache:
John

The application could remove the old cached value when the database is updated:

cache.invalidate(101);

The next request would then retrieve the updated value and place it back into the cache.

This approach can help maintain consistency between the cache and the underlying data source.

Cache Eviction

Expiration and eviction are related but aren’t exactly the same thing.

Expiration generally removes an entry because it has exceeded a time-based rule.

Eviction can remove an entry because the cache needs to free space or because an eviction policy has selected it.

For example, suppose a cache has a maximum size of 10,000 entries.

When the cache reaches its limit, it needs to decide which entries should be removed.

Common strategies include:

  • Least Recently Used (LRU)
  • Least Frequently Used (LFU)
  • Size-based eviction
  • Time-based expiration

A dedicated caching library can handle these mechanisms automatically.

How to Avoid Memory Problems

When creating an in-memory cache, memory usage should always be considered.

If an application stores thousands or millions of large objects, the cache can consume a significant amount of JVM memory.

For example:

Map<Integer, LargeObject> cache = new HashMap<>();

If entries are continuously added without limits, memory usage can grow.

A better design establishes boundaries:

Maximum Entries
       +
Expiration
       +
Eviction
       +
Monitoring

This makes cache behavior more predictable.

Should Every Java Object Be Cached?

No.

Caching everything is usually a poor strategy.

An object is a good caching candidate when:

  • It is accessed frequently.
  • It is expensive to retrieve or calculate.
  • It doesn’t change constantly.
  • Reusing it provides a measurable performance benefit.
  • Its memory footprint is reasonable.

An object may not be worth caching when it is:

  • Rarely accessed.
  • Extremely large.
  • Constantly changing.
  • Cheap to recreate.
  • Sensitive to stale data.

Caching should solve a performance problem rather than simply being added because an application can use it.

Local Java Cache vs Distributed Cache

The approaches discussed so far are primarily local in-memory caches.

The cache exists within the application process:

Java Application
      |
      v
JVM Memory
      |
      v
Local Cache

This can be extremely fast because the application doesn’t need to communicate with another server.

However, it creates a limitation when the application runs on multiple servers.

For example:

Server A → Local Cache A

Server B → Local Cache B

Server C → Local Cache C

The three caches may contain different versions of the same data.

A distributed caching system can provide a shared cache:

Server A ─┐
Server B ─┼──→ Shared Cache
Server C ─┘

Redis is a common option for this type of architecture.

Detailed instructions for storing Java objects in Redis are better handled separately because Redis introduces serialization, connection management, distributed access, TTL, and other considerations. If your application needs a shared cache across multiple servers, you can learn more about how to store objects in Redis cache using Java.

Best Practices for Creating a Java Cache

When implementing a cache, consider the following practices.

Define a Maximum Size

Don’t allow an in-memory cache to grow without limits.

Use Expiration

Set an appropriate TTL when cached data shouldn’t remain valid indefinitely.

Handle Cache Misses

Always define what happens when an object isn’t available.

Plan Invalidation

Determine how cached objects will be removed or updated when the original data changes.

Consider Thread Safety

For concurrent applications, use a data structure or caching library designed for concurrent access.

Monitor the Cache

Useful metrics include:

  • Hit rate
  • Miss rate
  • Eviction count
  • Entry count
  • Memory consumption
  • Load time
  • Average access latency

Avoid Excessive Object Sizes

Caching large object graphs can consume much more memory than expected.

Cache Based on Evidence

Use application performance data to determine which objects are worth caching.

Common Mistakes When Creating a Java Cache

Using HashMap in a Highly Concurrent Environment

A standard HashMap isn’t designed to be a general-purpose concurrent cache.

Never Expiring Entries

Unlimited retention can result in unnecessary memory usage and stale data.

Caching Large Objects Without Limits

Large objects can quickly consume available heap memory.

Ignoring Stale Data

A cache can improve speed while returning incorrect or outdated information if invalidation isn’t properly designed.

Caching Without Measuring Performance

A cache adds complexity. If it doesn’t meaningfully improve performance, it may not be worth maintaining.

Frequently Asked Questions

How do you create a cache object in Java?

The simplest method is to use a Java collection such as HashMap:

Map<String, Object> cache = new HashMap<>();

For concurrent applications, ConcurrentHashMap can be used. Production systems may benefit from a dedicated caching library with expiration and eviction support.

Can I use HashMap as a cache?

Yes. A HashMap can serve as a basic cache for simple use cases, but it doesn’t automatically provide features such as TTL, eviction, or advanced concurrency support.

Is ConcurrentHashMap good for caching?

ConcurrentHashMap can be useful for simple thread-safe in-memory caching scenarios. However, it is not a complete caching framework, so additional functionality may be required for expiration and eviction.

How do I expire objects from a Java cache?

You can implement expiration manually by storing an expiration timestamp with each entry, or use a caching library that provides TTL and expiration features.

What is the best way to cache Java objects?

There is no universal best approach. A simple map may be enough for a small application, while a dedicated caching library is generally more suitable when you need expiration, eviction, size limits, and other production features.

Does a Java cache store the actual object?

An in-memory Java cache can retain references to Java objects. The exact behavior depends on the cache implementation and how values are stored.

Can a Java cache cause memory problems?

Yes. If an application stores too many objects, keeps entries for too long, or caches large object graphs, the cache can consume significant JVM memory.

Final Thoughts

Creating a cache object in Java can be as simple as storing values in a HashMap, but real-world caching usually requires more careful design.

For basic applications, a map-based cache can demonstrate the fundamental concept:

cache.put(key, value);

For concurrent applications, ConcurrentHashMap provides a better foundation for shared access. When you need features such as expiration, maximum size, automatic loading, and eviction, a dedicated caching library can reduce the amount of custom code you need to maintain.

The most important part isn’t simply creating the cache. You also need to decide what should be cached, how long it should remain cached, when it should be invalidated, and how much memory the cache is allowed to consume.

For applications that run across multiple servers and need a shared cache, a distributed solution such as Redis can be more appropriate than keeping every cached object inside an individual JVM.

The next step is understanding how to store objects in Redis cache using Java, including serialization, TTL, storing Java object data, retrieving it, and handling distributed caching.

Author

Mudassar Ali

Follow Me
Other Articles
Java Object Cache
Previous

Java Object Cache: What It Is and How Object Caching Works

How to Store Objects in Redis Cache Using Java
Next

How to Store Objects in Redis Cache Using Java

No Comment! Be the first one.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

About the Author

Mudassar Ali

link builder

With years of experience in SEO and strategic link building, our founder is dedicated to helping websites achieve sustainable growth through ethical search engine optimization. Passionate about sharing practical insights, proven strategies, and the latest industry trends, they created this platform to provide valuable, results-driven content for marketers, business owners, and SEO professionals. Every article is crafted with a focus on accuracy, real-world experience, and long-term success in digital marketing.

  • Facebook
  • Instagram
  • LinkedIn
  • Pinterest
  • WhatsApp
Microsoft Fixes 570 Windows Vulnerabilities in Major Security Update

Microsoft has released a major security update fixing 570 vulnerabilities across Windows and related services. The update strengthens protection for critical system components and highlights how AI is helping Microsoft identify and resolve security threats faster. Users are strongly encouraged to install the latest updates to keep their devices secure against emerging cyber risks.

Where Ideas Find Clarity

Obvio.blogs is your trusted source for the latest insights in technology, AI, cybersecurity, SEO, digital marketing, web development, and emerging trends. Our mission is to deliver accurate, practical, and easy-to-understand content that keeps professionals, businesses, and tech enthusiasts informed in the fast-changing digital world.

  • Facebook
  • Instagram
  • Pinterest
  • Mail

Obvio.Blogs

Stay ahead with the latest in technology, AI, cybersecurity, SEO, web development, and digital trends. Simple, practical, and reliable content designed to keep you informed in the ever-evolving digital world.

mudassarali.linkbuilder@gmail.com

Copyright © 2026 Obvio Blogs. All rights reserved.