Java
Hash Table
Programming
Time Management in Coding
Data Structures

How would one change the value inside a hash table in Java based on the time that has elapsed?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If a value in a Java hash table needs to change after some amount of time, the map itself is not the hard part. The real design question is how you track time and when the update should happen. In most cases, that means storing metadata alongside the value or running a scheduled cleanup or refresh task.

The right solution depends on the behavior you want. Some systems update lazily when the entry is read. Others update eagerly on a timer. Those are different tradeoffs.

Store the Value Together With Time Metadata

The simplest pattern is to wrap the value together with a timestamp:

java
1class TimedValue<V> {
2    private V value;
3    private long lastUpdatedMillis;
4
5    TimedValue(V value) {
6        this.value = value;
7        this.lastUpdatedMillis = System.currentTimeMillis();
8    }
9
10    V getValue() {
11        return value;
12    }
13
14    void setValue(V value) {
15        this.value = value;
16        this.lastUpdatedMillis = System.currentTimeMillis();
17    }
18
19    long getLastUpdatedMillis() {
20        return lastUpdatedMillis;
21    }
22}

Then store that wrapper in your map:

java
Map<String, TimedValue<Integer>> map = new HashMap<>();
map.put("score", new TimedValue<>(10));

Now the map can answer both "what is the value" and "how old is it."

Lazy Update on Access

If the value should change only when someone reads it after enough time has passed, do the check during access:

java
1import java.util.HashMap;
2import java.util.Map;
3
4public class Demo {
5    private final Map<String, TimedValue<Integer>> map = new HashMap<>();
6
7    public int getValue(String key) {
8        TimedValue<Integer> entry = map.get(key);
9        if (entry == null) {
10            throw new IllegalArgumentException("Missing key: " + key);
11        }
12
13        long ageMillis = System.currentTimeMillis() - entry.getLastUpdatedMillis();
14        if (ageMillis > 5_000) {
15            entry.setValue(entry.getValue() + 1);
16        }
17
18        return entry.getValue();
19    }
20}

This approach is easy to reason about and avoids background work for entries that are never touched again.

Eager Update With a Scheduler

If entries must be updated or removed on a schedule even when nobody reads them, use a scheduler:

java
1import java.util.Map;
2import java.util.concurrent.ConcurrentHashMap;
3import java.util.concurrent.Executors;
4import java.util.concurrent.ScheduledExecutorService;
5import java.util.concurrent.TimeUnit;
6
7Map<String, TimedValue<Integer>> map = new ConcurrentHashMap<>();
8ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
9
10scheduler.scheduleAtFixedRate(() -> {
11    long now = System.currentTimeMillis();
12
13    for (Map.Entry<String, TimedValue<Integer>> entry : map.entrySet()) {
14        TimedValue<Integer> value = entry.getValue();
15        if (now - value.getLastUpdatedMillis() > 5_000) {
16            value.setValue(value.getValue() + 1);
17        }
18    }
19}, 0, 1, TimeUnit.SECONDS);

This is better when time-based behavior is part of the system contract rather than just a read-time convenience.

Prefer ConcurrentHashMap for Multi-Threaded Code

If background tasks and request threads access the map at the same time, HashMap is the wrong choice. Use ConcurrentHashMap and make your update logic explicit.

Java's map APIs can also help with atomic updates:

java
1map.computeIfPresent("score", (key, timed) -> {
2    long ageMillis = System.currentTimeMillis() - timed.getLastUpdatedMillis();
3    if (ageMillis > 5_000) {
4        timed.setValue(timed.getValue() + 1);
5    }
6    return timed;
7});

That is usually cleaner than a separate get followed by put.

Consider Whether a Cache Library Is Better

If your real requirement is expiration, refresh, or time-based invalidation, a cache library may fit better than a raw map. Libraries such as Caffeine already support expiration and refresh policies and are less error-prone than rebuilding cache behavior manually.

Use a plain map only when the time-based behavior is simple and truly specific to your domain.

Common Pitfalls

The biggest mistake is storing only the value and then trying to infer elapsed time later with no timestamp metadata. The map cannot do time-based logic unless you store time information somewhere.

Another common issue is using HashMap in code that is updated from multiple threads. Once scheduled tasks and request handlers both touch the map, concurrency matters immediately.

Developers also often skip the design decision between lazy update and eager scheduled update. Those strategies look similar in small examples, but they behave differently in production.

Finally, be careful not to turn a simple expiration problem into a hand-rolled cache when an existing cache library already solves it better.

Summary

  • A time-based value change in a Java map usually requires storing the value together with timestamp metadata.
  • Use lazy update on access when the change only matters when entries are read.
  • Use a scheduler when values must update or expire even without reads.
  • Prefer ConcurrentHashMap and atomic map operations in multi-threaded code.
  • Consider a cache library if the real problem is expiration or refresh rather than raw map mutation.

Course illustration
Course illustration

All Rights Reserved.