chinabugotech/hutool · error · UnsupportedOperationException

Cache values Iterator is not support to modify.

Error message

Cache values Iterator is not support to modify.

What it means

CacheObjIterator.remove() is intentionally unimplemented — the underlying cache does not support removing entries through its value iterator, so it throws UnsupportedOperationException. Hutool's cache iterator is read-only by design; mutation must go through the cache's own remove/evict API. Calling remove() on either the entry iterator or the value iterator derived from a CacheImpl will hit this.

Source

Thrown at hutool-cache/src/main/java/cn/hutool/cache/impl/CacheObjIterator.java:58

	/**
	 * @return 下一个值
	 */
	@Override
	public CacheObj<K, V> next() {
		if (false == hasNext()) {
			throw new NoSuchElementException();
		}
		final CacheObj<K, V> cachedObject = nextValue;
		nextValue();
		return cachedObject;
	}

	/**
	 * 从缓存中移除没有过期的当前值,此方法不支持
	 */
	@Override
	public void remove() {
		throw new UnsupportedOperationException("Cache values Iterator is not support to modify.");
	}

	/**
	 * 下一个值,当不存在则下一个值为null
	 */
	private void nextValue() {
		while (iterator.hasNext()) {
			nextValue = iterator.next();
			if (nextValue.isExpired() == false) {
				return;
			}
		}
		nextValue = null;
	}
}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Do not call remove() on the iterator; collect keys and remove them via Cache.remove(key) after iteration.
  2. Use cache.clear() or cache.prune() to evict rather than iterator mutation.
  3. If building a derived collection, copy entries into a new Map/List first, then mutate that.

Example fix

// before
Iterator<CacheObj<K,V>> it = cache.iterator();
while (it.hasNext()) { if (stale(it.next())) it.remove(); }
// after
List<K> toRemove = new ArrayList<>();
cache.forEach(it2 -> { if (stale(it2)) toRemove.add(it2.getKey()); });
toRemove.forEach(cache::remove);
Defensive patterns

Strategy: validation

Validate before calling

// never call iterator.remove() on a cache iterator; collect keys first
List<K> keys = new ArrayList<>();
cache.iterator().forEachRemaining(o -> { if (stale(o)) keys.add(o.getKey()); });
keys.forEach(cache::remove);

Try / catch

try { it.remove(); } catch (UnsupportedOperationException e) { /* use cache.remove(key) instead */ }

Prevention

When it happens

Trigger: Obtaining an iterator via cache.iterator(), cacheCacheObj.values().iterator(), or similar, then calling .remove() on it (often from enhanced-for loops that use Iterator.remove, or copy-by-filter utilities that mutate during iteration).

Common situations: Using Java streams/loops that expect a mutable iterator; writing a filter-and-prune routine against the cache directly instead of the cache API; porting code from a Map-based implementation.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/362fd4d6cfb707c6. Report an issue: GitHub.