Cache { public void cleanUp() { List<V> expiredEntries = new ArrayList<>(); _accessLock.lock(); try { long now = _timeSource.millis(); Iterator<Map.Entry<K, CacheElement<V>>> entries = _storage.entrySet().iterator(); while (entries.hasNext()) { Map.Entry<K, CacheElement<V>> entry = entries.next(); CacheElement<V> cacheElement = entry.getValue(); if (!cacheElement.validAt(now)) { _log.debug("Cleaning expired entry key = [{}], value = [{}]", entry.getKey(), cacheElement.getObject()); entries.remove(); expiredEntries.add(cacheElement.getObject()); } } _lastClean.set(now); } finally { _accessLock.unlock(); } expiredEntries.forEach( v -> _eventListener.notifyExpired(this, v)); } Cache(String name, int size, long entryLifeTime, long entryIdleTime);  Cache(final String name, int size, long entryLifeTime, long entryIdleTime,
            CacheEventListener<K, V> eventListener);  Cache(final String name, int size, long entryLifeTime, long entryIdleTime,
            CacheEventListener<K, V> eventListener, Clock clock); String getName(); void put(K k, V v); void put(K k, V v, long entryMaxLifeTime, long entryIdleTime); V get(K k); V remove(K k); long getEntryIdleTime(); long getEntryLiveTime(); void clear(); void cleanUp(); List<CacheElement<V>> entries(); long lastClean();  }
@Test public void testCleanUp() { _cache.put("key1", "value1", 1000, 1000); _cache.put("key2", "value2", 600, 600); _clock.advance(700, TimeUnit.MILLISECONDS); _cache.cleanUp(); assertEquals("unexpected number of elements", 1, _cache.size()); assertNotNull("Expected Entry expired", _cache.get("key1")); }