All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oloboke-api-jdk8.0.6.8.source-code.overview.html Maven / Gradle / Ivy

Go to download

Carefully designed and efficient extension of the Java Collections Framework with primitive specializations and more, built for Java 8 (API)

The newest version!


 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:
  1. 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.)

  2. 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.

  3. 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(map);}
 {@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 \ MutabilityMutableUpdatableImmutable
{@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 \ MutabilityMutableUpdatableImmutable
{@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

  1. 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.
  2. 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).
  3. 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)}
  4. 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.




© 2015 - 2024 Weber Informatics LLC | Privacy Policy