Skip navigation links

Package org.codefx.libfx.collection.transform

Provides transforming collections.

See: Description

Package org.codefx.libfx.collection.transform Description

Provides transforming collections.

Overview

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.

Details

The following details are important to use transforming collections without unexpected problems.

Forwarding

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.

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.

Type Safety

All operations on transforming collections are type safe in the usual static, compile-time way. But since many methods from the collection interfaces allow Objects (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.

Similar Features From Other Libraries

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.

Apache Commons Collections

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.

Google Guava

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.

Skip navigation links

This documentation is licensed under CC-BY 4.0, attributed to Nicolai Parlog from CodeFX.