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
inner.equals(toInner(toOuter(inner)) must be
true for all
inner elements. If this is not the case, the collections might behave in an
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
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
Collection.contains(Object)) or collections of unknown generic type
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.
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.