oloboke-api-jdk8.0.6.8.source-code.overview.html Maven / Gradle / Ivy
Show all versions of koloboke-api-jdk8 Show documentation
This library is a carefully designed and efficient extension of the Java Collections Framework
with primitive specializations and more.
Overview
With a few exceptions, the library API consists of three types of classes:
- Interface hierarchy, which generally repeats and extends Java Collection Framework (JCF)
interface and class hierarchy. Also, all interfaces are populated for all 7 primitive type
specializations, and "object specialization" for API symmetry (see
primitive specializations naming convention for more
information on this). For example, in JCF {@link java.util.HashSet} class extends
{@link java.util.Set} extends {@link java.util.Collection}. In this library
{@link net.openhft.koloboke.collect.set.hash.HashCharSet} interface extends
{@link net.openhft.koloboke.collect.set.CharSet}, which extends {@link java.util.Set} and
{@link net.openhft.koloboke.collect.CharCollection}, which extends
{@link java.util.Collection} and {@link net.openhft.koloboke.collect.Container}.
Also,
the {@code net.openhft.koloboke.function} package polyfills {@link java.util.function}
functional interface set with the rest specializations ({@link java.util.function} package
defines only some specializations for {@code int}, {@code long} and {@code double} types.)
- Factory interfaces, each of them defines several dozens of factory methods which
construct corresponding container interface instances. You can construct instances
of three mutability profiles. Factory interfaces also form
a hierarchy, which follow container's interface hierarchy, to ease making common
configurations. For example, you can define a method which accept
a {@link net.openhft.koloboke.collect.hash.HashContainerFactory} to configure all factories
which produce hash sets and maps in the application.
Note that all factories in the library are immutable, on changing any configuration a new
copy of the factory is returned, with the target configuration changed.
- Final uninstantiable classes for each "leaf" container and the corresponding factory
interface, which define the same set of static methods as the factory interface does,
all of them just delegate to the default factory instance, obtained via
{@link java.util.ServiceLoader}. This default factory instance is returned
by {@code getDefaultFactory()} static method in each static factory method holder class.
These classes have a name of container interface plus {@code -s} suffix, for example,
{@link net.openhft.koloboke.collect.map.hash.HashIntShortMaps} define static factory methods
which return {@link net.openhft.koloboke.collect.map.hash.HashIntShortMap} instances,
delegating to the default
{@link net.openhft.koloboke.collect.map.hash.HashIntShortMapFactory} implementation.
Table of equivalents of JDK collection patterns
JDK
The closest equivalent from this library
The recommended equivalent from this library
{@code new HashMap();}
{@code HashObjObjMaps.getDefaultFactory()
.withNullKeyAllowed(true)
.newMutableMap();}
{@code HashObjObjMaps.newUpdatableMap();}
{@code // unclear how "capacity" (100)
// is translated to size. 50? 75? 100?
new HashMap(100);}
{@code HashIntObjMaps.newMutableMap(
(int) (100 * HashConfig.getDefault().getTargetLoad()));}
{@code // 50 is expected _size_
HashIntObjMaps.newUpdatableMap(50);}
{@code new IdentityHashMap
{@code HashObjDoubleMaps.getDefaultFactory()
// these loads used in IdentityHashMap internally
.withHashConfig(HashConfig.fromLoads(1./3., 2./3., 2./3.))
.withNullKeyAllowed(true)
.withKeyEquivalence(Equivalence.identity())
.newMutableMap(map);}
{@code HashObjDoubleMaps.getDefaultFactory()
.withKeyEquivalence(Equivalence.identity())
.newImmutableMap(map);}
{@code Collections.unmodifiableSet(new HashSet<>() {{
add("Summer");
add("Autumn");
add("Winter");
add("Spring");
}});}
{@code HashObjSets.newImmutableSetOf("Summer", "Autumn", "Winter", "Spring");}
Mutability profiles
Container factories allow to construct containers with several distinct degrees of mutability.
It is useful for two main purposes: first, to defend your data from occasional (or intentional)
container misuse, i. e. the same purpose for what {@code Collections.unmodifiable*} methods
exist. Second, containers of lesser mutability are implemented in more efficient manner, whenever
possible. So using immutable collections when applicable could improve your application's
performance a bit.
Immutable
Any operations that change the conceptual container state, e. g. insertions and removals,
as well as that could touch internal representation,
e. g. {@link net.openhft.koloboke.collect.Container#shrink()}, are disallowed. Other ones
are allowed.
Updatable
Everything is allowed, except removals of individual elements (entries),
typically these operations' names contain word "remove" or "retain". Emphasis on "individual"
means that {@link net.openhft.koloboke.collect.Container#clear()} is allowed.
Think about updatable containers as "non-decreasing", which could be "reset"
from time to time by {@code clear()}.
In real practice individual removals are rarely needed, so most of the time you should use
updatable containers rather than fully mutable ones. On the other hand, prohibit of removals
permits faster implementation of {@linkplain net.openhft.koloboke.collect.hash.HashContainer hash
containers} and iterators over many data structures.
Mutable
All operations are allowed.
{@link java.util.Collection} mutability matrix
This matrix shows which methods of the {@link java.util.Collection}
interface are supported by collections with different mutability profiles.
Method \ Mutability Mutable Updatable Immutable
{@link java.util.Collection#contains(Object) contains(Object)}
✓ ✓ ✓
{@link java.util.Collection#containsAll(java.util.Collection) containsAll(Collection)}
✓ ✓ ✓
{@link java.util.Collection#iterator() iterator()}
✓ ✓ ✓
{@link java.util.Collection#toArray() toArray()}
✓ ✓ ✓
{@link java.util.Collection#toArray(Object[]) toArray(Object[])}
✓ ✓ ✓
{@link java.util.Collection#add(Object) add(Object)}
✓ ✓ -
{@link java.util.Collection#addAll(java.util.Collection) addAll(Collection)}
✓ ✓ -
{@link java.util.Collection#remove(Object) remove(Object)}
✓ - -
{@link java.util.Collection#removeAll(java.util.Collection) removeAll(Collection)}
✓ - -
{@link java.util.Collection#retainAll(java.util.Collection) retainAll(Collection)}
✓ - -
{@link java.util.Collection#removeIf(java.util.function.Predicate) removeIf(Predicate)}
✓ - -
{@link java.util.Map} mutability matrix
This matrix shows which methods of the {@link java.util.Map}
interface are supported by maps with different mutability profiles.
Method \ Mutability Mutable Updatable Immutable
{@link java.util.Map#containsKey(Object) containsKey(Object)}
✓ ✓ ✓
{@link java.util.Map#containsValue(Object) containsValue(Object)}
✓ ✓ ✓
{@link java.util.Map#get(Object) get(Object)}
✓ ✓ ✓
{@link java.util.Map#getOrDefault(Object, Object) getOrDefault(Object, Object)}
✓ ✓ ✓
{@link java.util.Map#keySet() keySet()}
✓ ✓ ✓
{@link java.util.Map#entrySet() entrySet()}
✓ ✓ ✓
{@link java.util.Map#values() values()}
✓ ✓ ✓
{@link java.util.Map#forEach(java.util.function.BiConsumer) forEach(BiConsumer)}
✓ ✓ ✓
{@link java.util.Map#put(Object, Object) put(Object, Object)}
✓ ✓ -
{@link java.util.Map#putIfAbsent(Object, Object) putIfAbsent(Object, Object)}
✓ ✓ -
{@link java.util.Map#computeIfAbsent(Object, java.util.function.Function)
computeIfAbsent(Object, Function)}
✓ ✓ -
{@link java.util.Map#replace(Object, Object) replace(Object, Object)}
✓ ✓ -
{@link java.util.Map#replace(Object, Object, Object) replace(Object, Object, Object)}
✓ ✓ -
{@link java.util.Map#putAll(java.util.Map) putAll(Map)}
✓ ✓ -
{@link java.util.Map#replaceAll(java.util.function.BiFunction) replaceAll(BiFunction)}
✓ ✓ -
{@link java.util.Map#compute(Object, java.util.function.BiFunction)
compute(Object, BiFunction)}
✓ ✓, except removing on returning {@code null} -
{@link java.util.Map#computeIfPresent(Object, java.util.function.BiFunction)
computeIfPresent(Object, BiFunction)}
✓ ✓, except removing on returning {@code null} -
{@link java.util.Map#merge(Object, Object, java.util.function.BiFunction)
merge(Object, Object, BiFunction)}
✓ ✓, except removing on returning {@code null} -
{@link java.util.Map#remove(Object) remove(Object)}
✓ - -
{@link java.util.Map#remove(Object, Object) remove(Object, Object)}
✓ - -
See other matrices for information if the concrete method is supported by the given
mutability profile: {@code Container}.
Comparison of iteration ways
In addition to the standard ways —
{@linkplain java.util.Iterator iterators} and {@code forEach()}-like methods
which accept closures, the library supplies {@linkplain
net.openhft.koloboke.collect.Cursor cursors} for every container
.
Overview comparison of the ways to iterate over containers within the library
{@link java.util.Iterator}
{@link net.openhft.koloboke.collect.Cursor}
{@code forEach()}
{@code forEachWhile()}
{@code removeIf()}
Available for {@link java.util.Collection} sub-interfaces in the library
Yes
Available for {@link java.util.Map} sub-interfaces in the library
Yes
Coding convenience
High, if elements aren't removed and generic version
of {@link java.util.Iterator#next()} method is used, Java "for-each" syntax
is applicable. Medium otherwise.
Medium
High, lambda syntax
Supports early break from the iteration
Yes, by simple break from the loop
Yes, by simple break from the loop
No
Yes, by returning {@code false}
No
Supports remove of iterated elements (entries)
Yes, by {@link java.util.Iterator#remove()}
Yes, by {@link net.openhft.koloboke.collect.Cursor#remove()}
No
No
Yes, by returning {@code true}
Performance, iteration over {@link java.util.Map}
Medium, {@link java.util.Map.Entry} objects are allocated
Very high
Performance, iteration over {@link java.util.Collection}
High, if specialized version of {@link java.util.Iterator#next()} method
is used. Medium otherwise, because every element is boxed.
Very high
Compatibility with Java Collections Framework
All containers from the library have least possible (given initial design decisions) semantic
difference with the most widely used implementation from JCF of the same parental interface.
For example, {@link net.openhft.koloboke.collect.set.hash.HashCharSet} extends
{@code java.util.Set}, and made as similar as possible
to {@code java.util.HashSet}, which extends the same interface. Non-obvious things,
made compatible with JCF in the library:
- Containers of objects support {@code null} elements, keys and values, despite this is
an antipattern, because most JCF implementations does. Important: hash maps and sets
with {@code Object} keys,
e. g. {@link net.openhft.koloboke.collect.map.hash.HashObjDoubleMap}, don't support
{@code null} key by default, you should configure
{@code factory.}{@link net.openhft.koloboke.collect.hash.ObjHashFactory#withNullKeyAllowed(boolean
) withNullKeyAllowed(true)}.
- All containers try to detect concurrent access to themselves, if at least one thread
modify the container structurally, and to throw
{@link java.util.ConcurrentModificationException} on best-effort basis, i. e. they have
fail-fast semantics. See documentation for {@code ConcurrentModificationException}
for more information.
- Although {@link java.lang.Float#NaN} {@code != Float.NaN} (similarly for {@code Double})
in Java, in this library in containers these values are treated consistently with their boxed
versions (i. e. {@code new Float(Float.NaN)}, all such objects are equal to each other.
Known incompatibilities
- Collections of primitives don't support {@code null} element, key or value. Obviously,
this is by design and can't be fixed.
- Collections don't implement {@link java.lang.Cloneable} yet. To be fixed, see
the issue.
- Collections don't implement {@link java.io.Serializable} yet. To be fixed, see
the issue.
- Hash sets and maps with {@code byte}, {@code char} or {@code short} keys
can't be complete, i. e. contain all keys of the type, unlike {@code HashSet
},
{@code HashSet} and {@code HashSet}. There should be 1-2 absent keys.
On attempt of insertion the last keys
{@link net.openhft.koloboke.collect.hash.HashOverflowException} is thrown.
- It is not guaranteed that any hash set or map implementation can hold more than
250 millions of elements or entries. {@code HashOverflowException} is thrown on attempt
of insertion an element or entry beyond the actual limit. {@code java.util.HashMap} and
{@code java.util.HashSet} have higher limit, if there is enough heap space.
Primitive specializations naming convention
- The name of the specialized class is the name of the "basic" class with prefix equal
to capitalized Java primitive type name of the element specialization, or key specialization
type name followed value specialization type name without anything in between. Examples:
{@link net.openhft.koloboke.collect.CharCollection} extends {@link java.util.Collection},
{@link net.openhft.koloboke.collect.map.IntFloatMap} extends {@link java.util.Map}.
There are also classes with {@code Obj-} prefix, they bring API
additions to collections of objects, if there are no additions for the class or
interface, {@code Obj-} "specializations" are present anyway, for global API symmetry.
- If the specialized method has arguments of the specialized type, it has the same name
as the non-specialized, thanks to Java's method overloading feature. There could be
compilation issues in the client code, due to ambiguity, if there are several specialized
arguments and some of them are boxed. You should "cast" them to unboxed values. For example:
{@code
IntIntMap map = HashIntIntMaps.newUpdatableMap();
Integer key = 1;
map.put(key, 2); // ambiguous method call
map.put((int) key, 2); // correct}
There is one exception from this rule:
{@link net.openhft.koloboke.collect.ByteCollection#removeByte(byte)} is a specialized version
of {@link java.util.Collection#remove(Object)}, but have a different name (the same
for {@link net.openhft.koloboke.collect.LongCollection},
{@link net.openhft.koloboke.collect.FloatCollection}, etc.
for symmetry. This is because {@code remove(int)}
in {@link net.openhft.koloboke.collect.IntCollection} will conflict with
{@link java.util.List#remove(int)} method in {@code IntList} (not implemented yet, however).
- If the specialized method doesn't have arguments of the specialized types, but return
the specialized type, capitalized primitive type name, optionally preceded by {@code -As-}
infix, is added to the original method name. Examples:
- {@link net.openhft.koloboke.collect.map.ObjCharMap#getChar(Object)}
- {@link net.openhft.koloboke.collect.map.ObjCharMap#removeAsChar(Object)}
- {@link net.openhft.koloboke.collect.CharIterator#nextChar()}
- {@link net.openhft.koloboke.function.ToCharFunction#applyAsChar(Object)}
- Method {@link net.openhft.koloboke.collect.DoubleCollection#toDoubleArray()}, and others
similar, is exceptional from those rules and have special name.
API additions beyond JCF interfaces
The library brings some extra functionality beyond implementing JCF interfaces and generating
primitive specializations for each interface and method.
The concept of pluggable element (key, value) equivalences
JCF interfaces and implementations rely on Java built-in equality and hash code infrastructure:
{@link java.lang.Object#equals(Object)} and {@link java.lang.Object#hashCode()}. Container
factories in the library allow to configure {@linkplain net.openhft.koloboke.collect.Equivalence
equivalences} for elements, keys and values. This allows to implement some functionality very
easy, without defining new subclasses of the existing collections implementations. See
the documentation to {@link net.openhft.koloboke.collect.ObjCollection#equivalence()},
{@link net.openhft.koloboke.collect.map.ObjObjMap#keyEquivalence()} and
{@link net.openhft.koloboke.collect.map.ObjObjMap#valueEquivalence()} methods for more
information.
Functional additions to {@link java.util.Collection} interface:
- {@link
net.openhft.koloboke.collect.ObjCollection#forEachWhile(java.util.function.Predicate)}
performs the given action for each element of the collection, while it returns {@code true}.
- Containers in the library support {@link net.openhft.koloboke.collect.Cursor} iteration:
{@link net.openhft.koloboke.collect.ObjCollection#cursor()}. See also
the comparison of iteration ways in the library.
Of cause, there are appropriate specialized methods in the {@link java.util.Collection} interface
primitive specializations: {@link net.openhft.koloboke.collect.ByteCollection},
{@link net.openhft.koloboke.collect.CharCollection}, etc.
Functional additions to {@link java.util.Map} interface:
- {@link net.openhft.koloboke.collect.map.ObjObjMap#cursor()} — cursor
iteration over maps.
- {@link
net.openhft.koloboke.collect.map.ObjObjMap#forEachWhile(java.util.function.BiPredicate)
} performs the given action for each entry of the map, while it returns {@code true}.
- {@link
net.openhft.koloboke.collect.map.ObjObjMap#removeIf(java.util.function.BiPredicate)}
removes all of the entries of this map that satisfy the given predicate.
- {@link net.openhft.koloboke.collect.map.ObjIntMap#addValue(Object, int)} and
{@link net.openhft.koloboke.collect.map.ObjIntMap#addValue(Object, int, int)} add
the given value to the value associated to the given key. These methods are present
in the map specializations with primitive value.
Additional control over hash table behaviour
The single thing in the API of JDK hash table implementations, including
{@link java.util.HashMap}, {@link java.util.LinkedHashMap}, {@link java.util.HashSet}
and {@link java.util.WeakHashMap}, that allows to control it's memory footprint and performance
characteristics, is {@code loadFactor} constructor argument. {@link java.util.IdentityHashMap}
don't have even this one. This library allows to tune hash tables very precisely via a bunch
of per-instance methods and factory configurations. See the documentation
to {@link net.openhft.koloboke.collect.hash.HashContainer} and
{@link net.openhft.koloboke.collect.hash.HashConfig} classes for more information.