Class | Description |
---|---|
EqualityTransformingCollectionBuilder<E> |
Builds
EqualityTransformingSet s and EqualityTransformingMap s. |
EqualityTransformingMap<K,V> | |
EqualityTransformingSet<E> | |
OptionalTransformingCollection<E> |
A transforming
Collection which is a flattened view on a collection of Optional s, i.e. |
OptionalTransformingList<E> | |
OptionalTransformingSet<E> | |
TransformingCollection<I,O> |
A
Collection which decorates another collection and transforms the element type from the inner type I
to an outer type O . |
TransformingCollectionBuilder<I,O> | |
TransformingIterator<I,O> |
An
Iterator which wraps another iterator and transforms the returned elements from their inner type I
to an outer type O . |
TransformingList<I,O> |
A
List which decorates another list and transforms the element type from the inner type I to an outer
type O . |
TransformingListIterator<I,O> |
A
ListIterator which wraps another list iterator and transforms elements from an inner type I to an
outer type O and vice versa. |
TransformingMap<IK,OK,IV,OV> |
A
Map which decorates another map and transforms the key and value types from the inner types IK ,
IV to outer types OK , OV . |
TransformingMapBuilder<IK,OK,IV,OV> |
Builder for
TransformingMap s. |
TransformingSet<I,O> |
A
Set which decorates another set and transforms the element type from the inner type I to an outer
type O . |
TransformingSpliterator<I,O> |
A
Spliterator which wraps another spliterator and transforms the returned elements from an inner type
I to an outer type O and vice versa. |
Provides transforming collections.
A transforming collection is essentially a decorator of an existing collection which transforms the collection's elements from one type to another. Note that all such classes are views! They operate on the wrapped collection and all changes to either of them is reflected in the other.
The decorated collection is usually referred to as the inner collection and it's generic type accordingly as the inner type. The transforming collection and its generic type are referred to as outer collection and outer type, respectively.
The following details are important to use transforming collections without unexpected problems.
Unless otherwise noted the views forward all method calls (of abstract and default methods existing in JDK 8) to the same method on the inner collection. This implies that all guarantees made by such methods (e.g. regarding atomicity) are upheld by the transformation.
The transformation is computed with a pair of functions. One is used to transform outer elements to inner elements
and another one for the other direction. In the case of a Map
two such pairs exist: one for
keys and one for values.
The transforming functions must be inverse to each other with regard to equals
, i.e. outer.equals(toOuter(toInner(outer))
and inner.equals(toInner(toOuter(inner))
must be
true for all outer
and inner
elements. If this is not the case, the collections might behave in an
unpredictable manner.
Note that the same is not true for identity, i.e. outer == toOuter(toInner(outer))
may be false. It is
explicitly allowed to create new outer elements from inner elements and vice versa. This means that outer elements
may have no meaningful identity. E.g. on adding an outer instance outerOrg
it can be transformed to
inner
and on access back to outer
. Whether outerOrg == outer
holds, depends on the
transformation functions and is generally unspecified - it might never, sometimes or always be true. Transforming
collections might give more details on their behavior regarding this.
A special case of transformation occurs when the inner and outer type have a type relationship. This can shortcut one of the transformations to the identity, i.e. because an instance of one type is also of the other type the corresponding transformation can simply return the instance itself. This makes the collection "leak" elements of the wrong type. If the suptype does not fully obey the Liskov Substitution Principle this can lead to unexpected behavior.
Transforming functions should have no side effects. No guarantees are made regarding how often transformations are called.
All operations on transforming collections are type safe in the usual static, compile-time way. But since many
methods from the collection interfaces allow Object
s (e.g
Collection.contains(Object)
) or collections of unknown generic type
(e.g Collection.addAll(Collection<?>)
) as arguments,
this does not cover all cases which can occur at runtime.
If one of those methods is called with a type which does not match the transforming collection's outer type the
method may throw a ClassCastException
. While this is in accordance with the
methods' contracts it might still be unexpected.
One way to circumvent this to pay close attention when using the collection and ensuring that such calls can not occur (which is often easy). Another way is to write wrappers which catch and silently ignore the exception.
To my (nipa's) knowledge two other libraries offer similar functionality, namely Apache Commons Collections and Google Guava. Both have shortcomings which this implementation aims to overcome.
Commons provides the TransformedCollection
. It only affects add methods,
"thus objects must be removed or searched for using their transformed form." The implementations in this package
suffer from no such limitation.
Guava contains a utility method transform(List, Function)
which returns a transformed view of the specified map. But
"the transform is one-way and new items cannot be stored in the returned list." The implementations in this package
explicitly allow editing both instances.
This documentation is licensed under CC-BY 4.0, attributed to Nicolai Parlog from CodeFX.