Class ClassValueMap<V>
- Type Parameters:
V- the type of mapped values
- All Implemented Interfaces:
ConcurrentMap<Class<?>,,V> Map<Class<?>,V>
Performance Advantages
ClassValueMap provides significantly faster get() operations compared to standard
Map implementations:
- 2-10x faster than HashMap for key lookups
- 3-15x faster than ConcurrentHashMap for concurrent access patterns
- The performance advantage increases with contention (multiple threads)
- Most significant when looking up the same class keys repeatedly
Typed fast path: getByClass(Class)
The standard get(Object) method must accept an Object and perform a runtime
instanceof Class guard before routing to the ClassValue cache (keys that are
not Class instances fall through to the backing ConcurrentHashMap). When the
caller already knows the key is a Class, getByClass(Class) skips that guard
entirely and compiles to a near-direct ClassValue.get(Class) call — a JIT-intrinsified,
identity-based per-Class load.
For performance-critical call sites, prefer getByClass(Class). To take advantage of it,
hold the field as ClassValueMap<V> (not Map<Class<?>, V>), so the compiler
resolves the typed lookup statically.
How It Works
The implementation utilizes Java's ClassValue mechanism, which is specially optimized
in the JVM through:
- Thread-local caching for reduced contention
- Identity-based lookups (faster than equality checks)
- Special VM support that connects directly to Class metadata structures
- Optimized memory layout that can reduce cache misses
Drop-in Replacement
ClassValueMap is designed as a drop-in replacement for existing maps with Class keys:
- Fully implements the
MapandConcurrentMapinterfaces - Supports all standard map operations (put, remove, clear, etc.)
- Handles null keys and null values just like standard map implementations
- Thread-safe for all operations
Ideal Use Cases
ClassValueMap is ideal for:
- High read-to-write ratio scenarios (read-mostly workloads)
- Caches for class-specific handlers, factories, or metadata
- Performance-critical operations in hot code paths
- Type registries in frameworks (serializers, converters, validators)
- Class capability or feature mappings
- Any system that frequently maps from Class objects to associated data
Trade-offs
The performance benefits come with some trade-offs:
- Higher memory usage (maintains both a backing map and ClassValue cache)
- Write operations (put/remove) aren't faster and may be slightly slower
- Only Class keys benefit from the optimized lookups
Thread Safety
This implementation is thread-safe for all operations and implements ConcurrentMap.
Usage Example
// Create a registry of class handlers
ClassValueMap<Handler> handlerRegistry = new ClassValueMap<>();
handlerRegistry.put(String.class, new StringHandler());
handlerRegistry.put(Integer.class, new IntegerHandler());
handlerRegistry.put(List.class, new ListHandler());
// Fast lookup in a performance-critical context — getByClass skips the
// instanceof-Class guard that get(Object) must perform.
public void process(Object obj) {
Handler handler = handlerRegistry.getByClass(obj.getClass());
if (handler != null) {
handler.handle(obj);
} else {
// Default handling
}
}
Important Performance Warning
Wrapping this class with standard collection wrappers like Collections.unmodifiableMap()
or Collections.newSetFromMap() will destroy the ClassValue performance benefits.
Always use the raw ClassValueMap directly or use the provided unmodifiableView() method
if immutability is required. Note that unmodifiableView() returns a
Map<Class<?>, V>, which does not expose getByClass(Class) — callers that need
the typed fast path should hold the view as a reference to the raw ClassValueMap.
- Author:
- John DeRegnaucourt ([email protected])
Copyright (c) Cedar Software LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
License
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - See Also:
-
Nested Class Summary
Nested classes/interfaces inherited from class java.util.AbstractMap
AbstractMap.SimpleEntry<K,V>, AbstractMap.SimpleImmutableEntry<K, V> -
Constructor Summary
ConstructorsConstructorDescriptionCreates a ClassValueMapClassValueMap(Map<? extends Class<?>, ? extends V> map) Creates a ClassValueMap containing the mappings from the specified map. -
Method Summary
Modifier and TypeMethodDescriptionvoidclear()computeIfAbsent(Class<?> key, Function<? super Class<?>, ? extends V> mappingFunction) booleancontainsKey(Object key) booleancontainsValue(Object value) entrySet()voidforEach(BiConsumer<? super Class<?>, ? super V> action) getByClass(Class<?> key) Typed-access companion toget(Object)for callers that already hold aClass<?>reference.booleanisEmpty()putIfAbsent(Class<?> key, V value) booleanbooleanintsize()Returns an unmodifiable view of this map that preserves ClassValue performance benefits.values()Methods inherited from class java.util.AbstractMap
clone, equals, hashCode, keySet, putAll, toStringMethods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, waitMethods inherited from interface java.util.concurrent.ConcurrentMap
computeIfPresent, getOrDefault, merge, replaceAll
-
Constructor Details
-
ClassValueMap
public ClassValueMap()Creates a ClassValueMap -
ClassValueMap
Creates a ClassValueMap containing the mappings from the specified map.- Parameters:
map- the map whose mappings are to be placed in this map- Throws:
NullPointerException- if the specified map is null
-
-
Method Details
-
get
-
getByClass
Typed-access companion toget(Object)for callers that already hold aClass<?>reference. Bypasses thekey.getClass() == Class.classtype guard thatget(Object)must perform because itsMapcontract takesObject. Results are identical toget(Object); the only difference is fewer instructions on the hot path.Null-safe: a null
keyreturns the current null-key mapping (ornullif none), matching the semantics ofget(Object)with anullargument.Use this method anywhere the caller has a
Class<?>in hand — internal caches, type registries, annotation metadata lookups, conversion dispatch tables, etc. The saved work is small per call (aGETFIELD+CMP+ branch + a cast the JIT doesn't always elide), but adds up across the millions of calls per second that a library like this sees through its hot paths.- Parameters:
key- the class key, ornull- Returns:
- the mapped value, or
nullif no mapping exists (or if the null key has no mapping, for anullargument) - See Also:
-
put
-
remove
-
containsKey
- Specified by:
containsKeyin interfaceMap<Class<?>,V> - Overrides:
containsKeyin classAbstractMap<Class<?>,V>
-
clear
public void clear() -
size
public int size() -
isEmpty
public boolean isEmpty() -
containsValue
- Specified by:
containsValuein interfaceMap<Class<?>,V> - Overrides:
containsValuein classAbstractMap<Class<?>,V>
-
forEach
-
entrySet
-
putIfAbsent
- Specified by:
putIfAbsentin interfaceConcurrentMap<Class<?>,V> - Specified by:
putIfAbsentin interfaceMap<Class<?>,V>
-
computeIfAbsent
Overridden to correctly handle null-value mappings. The default ConcurrentMap implementation cannot distinguish between "key absent" and "key maps to null" (both return null from get()), causing the computed value to be returned without actually being stored when a null-value mapping exists.
- Specified by:
computeIfAbsentin interfaceConcurrentMap<Class<?>,V> - Specified by:
computeIfAbsentin interfaceMap<Class<?>,V>
-
compute
public V compute(Class<?> key, BiFunction<? super Class<?>, ? super V, ? extends V> remappingFunction) Overridden to correctly handle null-value mappings. The default ConcurrentMap implementation uses
putIfAbsent()whenget()returns null, butputIfAbsent()returns null for both "inserted successfully" and "existing value is null," causing incorrect behavior. -
remove
-
replace
-
replace
-
values
-
unmodifiableView
Returns an unmodifiable view of this map that preserves ClassValue performance benefits. Unlike Collections.unmodifiableMap(), this method returns a view that maintains the fast lookup performance for Class keys.- Returns:
- an unmodifiable view of this map with preserved performance characteristics
-