69. Реализация класса с истекающими ключами #
🔥 Написать класс, который позволяет сохранять пары ключ-значение, где каждому ключу ассоциировано время действия. После истечения этого интервала ключ должен стать недоступным.
Методы класса:
set(String key, String value, int duration)
Принимает ключ в виде строки, значение типа
String
и длительность в миллисекундах.Ключ становится недоступным после истечения указанной длительности.
Метод возвращает
true
, если такой же ключ, который ещё не истек, уже существует, иfalse
в противном случае.Значение и длительность должны быть перезаписаны, если ключ уже существует.
get(String key)
Если существует неистекший ключ, метод возвращает связанное с ним значение.
В противном случае метод возвращает
-1
.
count()
- Возвращает количество ключей, срок действия которых не истек.
Спойлеры к решению
Подсказки
💡 Удобно хранить не только значение, но и время истечения — лучше в отдельном классе.
💡 Для потокобезопасности стоит использовать
💡 Проверку истечения (
💡 При
💡 Для потокобезопасности стоит использовать
ConcurrentHashMap
.💡 Проверку истечения (
isExpired
) нужно делать при каждом get
и count
.💡 При
count()
можно чистить карту от устаревших ключей.Решение
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ExpiringMap {
private static class ValueWithExpiry {
String value;
long expiryTime;
ValueWithExpiry(String value, long duration) {
this.value = value;
this.expiryTime = System.currentTimeMillis() + duration;
}
boolean isExpired() {
return System.currentTimeMillis() > expiryTime;
}
}
private final Map<String, ValueWithExpiry> storage = new ConcurrentHashMap<>();
public boolean set(String key, String value, int duration) {
ValueWithExpiry existing = storage.get(key);
boolean existedAndNotExpired = existing != null && !existing.isExpired();
storage.put(key, new ValueWithExpiry(value, duration));
return existedAndNotExpired;
}
public String get(String key) {
ValueWithExpiry v = storage.get(key);
if (v == null || v.isExpired()) {
storage.remove(key);
return "-1";
}
return v.value;
}
public int count() {
storage.entrySet().removeIf(entry -> entry.getValue().isExpired());
return storage.size();
}
}