/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections4.collection;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.iterators.EmptyIterator;
import org.apache.commons.collections4.iterators.IteratorChain;
import org.apache.commons.collections4.list.UnmodifiableList;
Decorates a collection of other collections to provide a single unified view.
Changes made to this collection will actually be made on the decorated collection.
Add and remove operations require the use of a pluggable strategy. If no
strategy is provided then add and remove are unsupported.
Type parameters: - <E> – the type of the elements in the collection
Since: 3.0
/**
* Decorates a collection of other collections to provide a single unified view.
* <p>
* Changes made to this collection will actually be made on the decorated collection.
* Add and remove operations require the use of a pluggable strategy. If no
* strategy is provided then add and remove are unsupported.
* </p>
* @param <E> the type of the elements in the collection
* @since 3.0
*/
public class CompositeCollection<E> implements Collection<E>, Serializable {
Serialization version /** Serialization version */
private static final long serialVersionUID = 8417515734108306801L;
CollectionMutator to handle changes to the collection /** CollectionMutator to handle changes to the collection */
private CollectionMutator<E> mutator;
Collections in the composite /** Collections in the composite */
private final List<Collection<E>> all = new ArrayList<>();
Create an empty CompositeCollection.
/**
* Create an empty CompositeCollection.
*/
public CompositeCollection() {
super();
}
Create a Composite Collection with one collection.
Params: - compositeCollection – the Collection to be appended to the composite
/**
* Create a Composite Collection with one collection.
*
* @param compositeCollection the Collection to be appended to the composite
*/
public CompositeCollection(final Collection<E> compositeCollection) {
super();
addComposited(compositeCollection);
}
Create a Composite Collection with two collections.
Params: - compositeCollection1 – the Collection to be appended to the composite
- compositeCollection2 – the Collection to be appended to the composite
/**
* Create a Composite Collection with two collections.
*
* @param compositeCollection1 the Collection to be appended to the composite
* @param compositeCollection2 the Collection to be appended to the composite
*/
public CompositeCollection(final Collection<E> compositeCollection1,
final Collection<E> compositeCollection2) {
super();
addComposited(compositeCollection1, compositeCollection2);
}
Create a Composite Collection with an array of collections.
Params: - compositeCollections – the collections to composite
/**
* Create a Composite Collection with an array of collections.
*
* @param compositeCollections the collections to composite
*/
public CompositeCollection(final Collection<E>... compositeCollections) {
super();
addComposited(compositeCollections);
}
//-----------------------------------------------------------------------
Gets the size of this composite collection.
This implementation calls size()
on each collection.
Returns: total number of elements in all contained containers
/**
* Gets the size of this composite collection.
* <p>
* This implementation calls <code>size()</code> on each collection.
* </p>
* @return total number of elements in all contained containers
*/
@Override
public int size() {
int size = 0;
for (final Collection<E> item : all) {
size += item.size();
}
return size;
}
Checks whether this composite collection is empty.
This implementation calls isEmpty()
on each collection.
Returns: true if all of the contained collections are empty
/**
* Checks whether this composite collection is empty.
* <p>
* This implementation calls <code>isEmpty()</code> on each collection.
* </p>
* @return true if all of the contained collections are empty
*/
@Override
public boolean isEmpty() {
for (final Collection<E> item : all) {
if (item.isEmpty() == false) {
return false;
}
}
return true;
}
Checks whether this composite collection contains the object.
This implementation calls contains()
on each collection.
Params: - obj – the object to search for
Returns: true if obj is contained in any of the contained collections
/**
* Checks whether this composite collection contains the object.
* <p>
* This implementation calls <code>contains()</code> on each collection.
* </p>
* @param obj the object to search for
* @return true if obj is contained in any of the contained collections
*/
@Override
public boolean contains(final Object obj) {
for (final Collection<E> item : all) {
if (item.contains(obj)) {
return true;
}
}
return false;
}
Gets an iterator over all the collections in this composite.
This implementation uses an IteratorChain
.
See Also: Returns: an IteratorChain
instance which supports
remove()
. Iteration occurs over contained collections in
the order they were added, but this behavior should not be relied upon.
/**
* Gets an iterator over all the collections in this composite.
* <p>
* This implementation uses an <code>IteratorChain</code>.
* </p>
* @return an <code>IteratorChain</code> instance which supports
* <code>remove()</code>. Iteration occurs over contained collections in
* the order they were added, but this behavior should not be relied upon.
* @see IteratorChain
*/
@Override
public Iterator<E> iterator() {
if (all.isEmpty()) {
return EmptyIterator.<E>emptyIterator();
}
final IteratorChain<E> chain = new IteratorChain<>();
for (final Collection<E> item : all) {
chain.addIterator(item.iterator());
}
return chain;
}
Returns an array containing all of the elements in this composite.
Returns: an object array of all the elements in the collection
/**
* Returns an array containing all of the elements in this composite.
*
* @return an object array of all the elements in the collection
*/
@Override
public Object[] toArray() {
final Object[] result = new Object[size()];
int i = 0;
for (final Iterator<E> it = iterator(); it.hasNext(); i++) {
result[i] = it.next();
}
return result;
}
Returns an object array, populating the supplied array if possible.
See Collection
interface for full details.
Params: - array – the array to use, populating if possible
Type parameters: - <T> – the type of the elements in the collection
Returns: an array of all the elements in the collection
/**
* Returns an object array, populating the supplied array if possible.
* See <code>Collection</code> interface for full details.
*
* @param <T> the type of the elements in the collection
* @param array the array to use, populating if possible
* @return an array of all the elements in the collection
*/
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(final T[] array) {
final int size = size();
Object[] result = null;
if (array.length >= size) {
result = array;
} else {
result = (Object[]) Array.newInstance(array.getClass().getComponentType(), size);
}
int offset = 0;
for (final Collection<E> item : all) {
for (final E e : item) {
result[offset++] = e;
}
}
if (result.length > size) {
result[size] = null;
}
return (T[]) result;
}
Adds an object to the collection, throwing UnsupportedOperationException
unless a CollectionMutator strategy is specified.
Params: - obj – the object to add
Throws: - UnsupportedOperationException – if CollectionMutator hasn't been set
- UnsupportedOperationException – if add is unsupported
- ClassCastException – if the object cannot be added due to its type
- NullPointerException – if the object cannot be added because its null
- IllegalArgumentException – if the object cannot be added
Returns: true
if the collection was modified
/**
* Adds an object to the collection, throwing UnsupportedOperationException
* unless a CollectionMutator strategy is specified.
*
* @param obj the object to add
* @return {@code true} if the collection was modified
* @throws UnsupportedOperationException if CollectionMutator hasn't been set
* @throws UnsupportedOperationException if add is unsupported
* @throws ClassCastException if the object cannot be added due to its type
* @throws NullPointerException if the object cannot be added because its null
* @throws IllegalArgumentException if the object cannot be added
*/
@Override
public boolean add(final E obj) {
if (mutator == null) {
throw new UnsupportedOperationException(
"add() is not supported on CompositeCollection without a CollectionMutator strategy");
}
return mutator.add(this, all, obj);
}
Removes an object from the collection, throwing UnsupportedOperationException
unless a CollectionMutator strategy is specified.
Params: - obj – the object being removed
Throws: - UnsupportedOperationException – if removed is unsupported
- ClassCastException – if the object cannot be removed due to its type
- NullPointerException – if the object cannot be removed because its null
- IllegalArgumentException – if the object cannot be removed
Returns: true if the collection is changed
/**
* Removes an object from the collection, throwing UnsupportedOperationException
* unless a CollectionMutator strategy is specified.
*
* @param obj the object being removed
* @return true if the collection is changed
* @throws UnsupportedOperationException if removed is unsupported
* @throws ClassCastException if the object cannot be removed due to its type
* @throws NullPointerException if the object cannot be removed because its null
* @throws IllegalArgumentException if the object cannot be removed
*/
@Override
public boolean remove(final Object obj) {
if (mutator == null) {
throw new UnsupportedOperationException(
"remove() is not supported on CompositeCollection without a CollectionMutator strategy");
}
return mutator.remove(this, all, obj);
}
Checks whether this composite contains all the elements in the specified collection.
This implementation calls contains()
for each element in the
specified collection.
Params: - coll – the collection to check for
Returns: true if all elements contained
/**
* Checks whether this composite contains all the elements in the specified collection.
* <p>
* This implementation calls <code>contains()</code> for each element in the
* specified collection.
* </p>
* @param coll the collection to check for
* @return true if all elements contained
*/
@Override
public boolean containsAll(final Collection<?> coll) {
if (coll == null) {
return false;
}
for (final Object item : coll) {
if (contains(item) == false) {
return false;
}
}
return true;
}
Adds a collection of elements to this collection, throwing
UnsupportedOperationException unless a CollectionMutator strategy is specified.
Params: - coll – the collection to add
Throws: - UnsupportedOperationException – if CollectionMutator hasn't been set
- UnsupportedOperationException – if add is unsupported
- ClassCastException – if the object cannot be added due to its type
- NullPointerException – if the object cannot be added because its null
- IllegalArgumentException – if the object cannot be added
Returns: true if the collection was modified
/**
* Adds a collection of elements to this collection, throwing
* UnsupportedOperationException unless a CollectionMutator strategy is specified.
*
* @param coll the collection to add
* @return true if the collection was modified
* @throws UnsupportedOperationException if CollectionMutator hasn't been set
* @throws UnsupportedOperationException if add is unsupported
* @throws ClassCastException if the object cannot be added due to its type
* @throws NullPointerException if the object cannot be added because its null
* @throws IllegalArgumentException if the object cannot be added
*/
@Override
public boolean addAll(final Collection<? extends E> coll) {
if (mutator == null) {
throw new UnsupportedOperationException(
"addAll() is not supported on CompositeCollection without a CollectionMutator strategy");
}
return mutator.addAll(this, all, coll);
}
Removes the elements in the specified collection from this composite collection.
This implementation calls removeAll
on each collection.
Params: - coll – the collection to remove
Throws: - UnsupportedOperationException – if removeAll is unsupported
Returns: true if the collection was modified
/**
* Removes the elements in the specified collection from this composite collection.
* <p>
* This implementation calls <code>removeAll</code> on each collection.
* </p>
* @param coll the collection to remove
* @return true if the collection was modified
* @throws UnsupportedOperationException if removeAll is unsupported
*/
@Override
public boolean removeAll(final Collection<?> coll) {
if (CollectionUtils.isEmpty(coll)) {
return false;
}
boolean changed = false;
for (final Collection<E> item : all) {
changed |= item.removeAll(coll);
}
return changed;
}
Removes all of the elements of this collection that satisfy the given predicate from this composite collection.
This implementation calls removeIf
on each collection.
Params: - filter – a predicate which returns true for elements to be removed
Throws: - UnsupportedOperationException – if removeIf is unsupported
Returns: true if the collection was modified Since: 4.4
/**
* Removes all of the elements of this collection that satisfy the given predicate from this composite collection.
* <p>
* This implementation calls <code>removeIf</code> on each collection.
* </p>
* @param filter a predicate which returns true for elements to be removed
* @return true if the collection was modified
* @throws UnsupportedOperationException if removeIf is unsupported
* @since 4.4
*/
@Override
public boolean removeIf(final Predicate<? super E> filter) {
if (Objects.isNull(filter)) {
return false;
}
boolean changed = false;
for (final Collection<E> item : all) {
changed |= item.removeIf(filter);
}
return changed;
}
Retains all the elements in the specified collection in this composite collection,
removing all others.
This implementation calls retainAll()
on each collection.
Params: - coll – the collection to remove
Throws: - UnsupportedOperationException – if retainAll is unsupported
Returns: true if the collection was modified
/**
* Retains all the elements in the specified collection in this composite collection,
* removing all others.
* <p>
* This implementation calls <code>retainAll()</code> on each collection.
* </p>
* @param coll the collection to remove
* @return true if the collection was modified
* @throws UnsupportedOperationException if retainAll is unsupported
*/
@Override
public boolean retainAll(final Collection<?> coll) {
boolean changed = false;
if (coll != null) {
for (final Collection<E> item : all) {
changed |= item.retainAll(coll);
}
}
return changed;
}
Removes all of the elements from this collection .
This implementation calls clear()
on each collection.
Throws: - UnsupportedOperationException – if clear is unsupported
/**
* Removes all of the elements from this collection .
* <p>
* This implementation calls <code>clear()</code> on each collection.
* </p>
* @throws UnsupportedOperationException if clear is unsupported
*/
@Override
public void clear() {
for (final Collection<E> coll : all) {
coll.clear();
}
}
//-----------------------------------------------------------------------
Specify a CollectionMutator strategy instance to handle changes.
Params: - mutator – the mutator to use
/**
* Specify a CollectionMutator strategy instance to handle changes.
*
* @param mutator the mutator to use
*/
public void setMutator(final CollectionMutator<E> mutator) {
this.mutator = mutator;
}
Add these Collections to the list of collections in this composite
Params: - compositeCollection – the Collection to be appended to the composite
/**
* Add these Collections to the list of collections in this composite
*
* @param compositeCollection the Collection to be appended to the composite
*/
public void addComposited(final Collection<E> compositeCollection) {
if (compositeCollection != null) {
all.add(compositeCollection);
}
}
Add these Collections to the list of collections in this composite
Params: - compositeCollection1 – the Collection to be appended to the composite
- compositeCollection2 – the Collection to be appended to the composite
/**
* Add these Collections to the list of collections in this composite
*
* @param compositeCollection1 the Collection to be appended to the composite
* @param compositeCollection2 the Collection to be appended to the composite
*/
public void addComposited(final Collection<E> compositeCollection1,
final Collection<E> compositeCollection2) {
if (compositeCollection1 != null) {
all.add(compositeCollection1);
}
if (compositeCollection2 != null) {
all.add(compositeCollection2);
}
}
Add these Collections to the list of collections in this composite
Params: - compositeCollections – the Collections to be appended to the composite
/**
* Add these Collections to the list of collections in this composite
*
* @param compositeCollections the Collections to be appended to the composite
*/
public void addComposited(final Collection<E>... compositeCollections) {
for (Collection<E> compositeCollection : compositeCollections) {
if (compositeCollection != null) {
all.add(compositeCollection);
}
}
}
Removes a collection from the those being decorated in this composite.
Params: - coll – collection to be removed
/**
* Removes a collection from the those being decorated in this composite.
*
* @param coll collection to be removed
*/
public void removeComposited(final Collection<E> coll) {
all.remove(coll);
}
//-----------------------------------------------------------------------
Returns a new collection containing all of the elements
Returns: A new ArrayList containing all of the elements in this composite.
The new collection is not backed by this composite.
/**
* Returns a new collection containing all of the elements
*
* @return A new ArrayList containing all of the elements in this composite.
* The new collection is <i>not</i> backed by this composite.
*/
public Collection<E> toCollection() {
return new ArrayList<>(this);
}
Gets the collections being decorated.
Returns: Unmodifiable list of all collections in this composite.
/**
* Gets the collections being decorated.
*
* @return Unmodifiable list of all collections in this composite.
*/
public List<Collection<E>> getCollections() {
return UnmodifiableList.unmodifiableList(all);
}
Get the collection mutator to be used for this CompositeCollection.
Returns: CollectionMutator<E>
/**
* Get the collection mutator to be used for this CompositeCollection.
* @return CollectionMutator<E>
*/
protected CollectionMutator<E> getMutator() {
return mutator;
}
//-----------------------------------------------------------------------
Pluggable strategy to handle changes to the composite.
Type parameters: - <E> – the element being held in the collection
/**
* Pluggable strategy to handle changes to the composite.
*
* @param <E> the element being held in the collection
*/
public interface CollectionMutator<E> extends Serializable {
Called when an object is to be added to the composite.
Params: - composite – the CompositeCollection being changed
- collections – all of the Collection instances in this CompositeCollection
- obj – the object being added
Throws: - UnsupportedOperationException – if add is unsupported
- ClassCastException – if the object cannot be added due to its type
- NullPointerException – if the object cannot be added because its null
- IllegalArgumentException – if the object cannot be added
Returns: true if the collection is changed
/**
* Called when an object is to be added to the composite.
*
* @param composite the CompositeCollection being changed
* @param collections all of the Collection instances in this CompositeCollection
* @param obj the object being added
* @return true if the collection is changed
* @throws UnsupportedOperationException if add is unsupported
* @throws ClassCastException if the object cannot be added due to its type
* @throws NullPointerException if the object cannot be added because its null
* @throws IllegalArgumentException if the object cannot be added
*/
boolean add(CompositeCollection<E> composite, List<Collection<E>> collections, E obj);
Called when a collection is to be added to the composite.
Params: - composite – the CompositeCollection being changed
- collections – all of the Collection instances in this CompositeCollection
- coll – the collection being added
Throws: - UnsupportedOperationException – if add is unsupported
- ClassCastException – if the object cannot be added due to its type
- NullPointerException – if the object cannot be added because its null
- IllegalArgumentException – if the object cannot be added
Returns: true if the collection is changed
/**
* Called when a collection is to be added to the composite.
*
* @param composite the CompositeCollection being changed
* @param collections all of the Collection instances in this CompositeCollection
* @param coll the collection being added
* @return true if the collection is changed
* @throws UnsupportedOperationException if add is unsupported
* @throws ClassCastException if the object cannot be added due to its type
* @throws NullPointerException if the object cannot be added because its null
* @throws IllegalArgumentException if the object cannot be added
*/
boolean addAll(CompositeCollection<E> composite,
List<Collection<E>> collections,
Collection<? extends E> coll);
Called when an object is to be removed to the composite.
Params: - composite – the CompositeCollection being changed
- collections – all of the Collection instances in this CompositeCollection
- obj – the object being removed
Throws: - UnsupportedOperationException – if removed is unsupported
- ClassCastException – if the object cannot be removed due to its type
- NullPointerException – if the object cannot be removed because its null
- IllegalArgumentException – if the object cannot be removed
Returns: true if the collection is changed
/**
* Called when an object is to be removed to the composite.
*
* @param composite the CompositeCollection being changed
* @param collections all of the Collection instances in this CompositeCollection
* @param obj the object being removed
* @return true if the collection is changed
* @throws UnsupportedOperationException if removed is unsupported
* @throws ClassCastException if the object cannot be removed due to its type
* @throws NullPointerException if the object cannot be removed because its null
* @throws IllegalArgumentException if the object cannot be removed
*/
boolean remove(CompositeCollection<E> composite,
List<Collection<E>> collections,
Object obj);
}
}