diff --git a/src/main/java/org/apache/commons/collections4/SetUtils.java b/src/main/java/org/apache/commons/collections4/SetUtils.java index 3d24cb271..f95a5e780 100644 --- a/src/main/java/org/apache/commons/collections4/SetUtils.java +++ b/src/main/java/org/apache/commons/collections4/SetUtils.java @@ -17,6 +17,7 @@ package org.apache.commons.collections4; import java.util.AbstractSet; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -47,14 +48,56 @@ import org.apache.commons.collections4.set.UnmodifiableSortedSet; public class SetUtils { /** - * Get a typed empty unmodifiable Set. + * An unmodifiable view of a set that may be backed by other sets. + *

+ * If the decorated sets change, this view will change as well. The contents + * of this view can be transferred to another instance via the {@link #copyInto(Set)} + * and {@link #toSet()} methods. + * * @param the element type - * @return an empty Set + * @since 4.1 */ - public static Set emptySet() { - return Collections.emptySet(); - } + public static abstract class SetView extends AbstractSet { + /** + * Copies the contents of this view into the provided set. + * + * @param the set type + * @param set the set for copying the contents + */ + public > void copyInto(final S set) { + CollectionUtils.addAll(set, this); + } + + /** + * Return an iterator for this view; the returned iterator is + * not required to be unmodifiable. + * @return a new iterator for this view + */ + protected abstract Iterator createIterator(); + + @Override + public Iterator iterator() { + return IteratorUtils.unmodifiableIterator(createIterator()); + } + + @Override + public int size() { + return IteratorUtils.size(iterator()); + } + + /** + * Returns a new set containing the contents of this view. + * + * @return a new set containing all elements of this view + */ + public Set toSet() { + final Set set = new HashSet<>(size()); + copyInto(set); + return set; + } + } + /** * An empty unmodifiable sorted set. * This is not provided in the JDK. @@ -63,410 +106,6 @@ public class SetUtils { public static final SortedSet EMPTY_SORTED_SET = UnmodifiableSortedSet.unmodifiableSortedSet(new TreeSet<>()); - /** - * Get a typed empty unmodifiable sorted set. - * @param the element type - * @return an empty sorted Set - */ - @SuppressWarnings("unchecked") // empty set is OK for any type - public static SortedSet emptySortedSet() { - return EMPTY_SORTED_SET; - } - - /** - * SetUtils should not normally be instantiated. - */ - private SetUtils() {} - - //----------------------------------------------------------------------- - - /** - * Returns an immutable empty set if the argument is null, - * or the argument itself otherwise. - * - * @param the element type - * @param set the set, possibly null - * @return an empty set if the argument is null - */ - public static Set emptyIfNull(final Set set) { - return set == null ? Collections.emptySet() : set; - } - - /** - * Tests two sets for equality as per the equals() contract - * in {@link java.util.Set#equals(java.lang.Object)}. - *

- * This method is useful for implementing Set when you cannot - * extend AbstractSet. The method takes Collection instances to enable other - * collection types to use the Set implementation algorithm. - *

- * The relevant text (slightly paraphrased as this is a static method) is: - *

- *

Two sets are considered equal if they have - * the same size, and every member of the first set is contained in - * the second. This ensures that the {@code equals} method works - * properly across different implementations of the {@code Set} - * interface.

- * - *

- * This implementation first checks if the two sets are the same object: - * if so it returns {@code true}. Then, it checks if the two sets are - * identical in size; if not, it returns false. If so, it returns - * {@code a.containsAll((Collection) b)}.

- *
- * - * @see java.util.Set - * @param set1 the first set, may be null - * @param set2 the second set, may be null - * @return whether the sets are equal by value comparison - */ - public static boolean isEqualSet(final Collection set1, final Collection set2) { - if (set1 == set2) { - return true; - } - if (set1 == null || set2 == null || set1.size() != set2.size()) { - return false; - } - - return set1.containsAll(set2); - } - - /** - * Generates a hash code using the algorithm specified in - * {@link java.util.Set#hashCode()}. - *

- * This method is useful for implementing Set when you cannot - * extend AbstractSet. The method takes Collection instances to enable other - * collection types to use the Set implementation algorithm. - * - * @param the element type - * @see java.util.Set#hashCode() - * @param set the set to calculate the hash code for, may be null - * @return the hash code - */ - public static int hashCodeForSet(final Collection set) { - if (set == null) { - return 0; - } - - int hashCode = 0; - for (final T obj : set) { - if (obj != null) { - hashCode += obj.hashCode(); - } - } - return hashCode; - } - - /** - * Returns a new hash set that matches elements based on == not - * equals(). - *

- * This set will violate the detail of various Set contracts. - * As a general rule, don't compare this set to other sets. In particular, you can't - * use decorators like {@link ListOrderedSet} on it, which silently assume that these - * contracts are fulfilled. - *

- * Note that the returned set is not synchronized and is not thread-safe. - * If you wish to use this set from multiple threads concurrently, you must use - * appropriate synchronization. The simplest approach is to wrap this map - * using {@link java.util.Collections#synchronizedSet(Set)}. This class may throw - * exceptions when accessed by concurrent threads without synchronization. - * - * @param the element type - * @return a new identity hash set - * @since 4.1 - */ - public static Set newIdentityHashSet() { - return Collections.newSetFromMap(new IdentityHashMap()); - } - - // Set - //----------------------------------------------------------------------- - /** - * Returns a synchronized set backed by the given set. - *

- * You must manually synchronize on the returned set's iterator to - * avoid non-deterministic behavior: - * - *

-     * Set s = SetUtils.synchronizedSet(mySet);
-     * synchronized (s) {
-     *     Iterator i = s.iterator();
-     *     while (i.hasNext()) {
-     *         process (i.next());
-     *     }
-     * }
-     * 
- * - * This method is just a wrapper for {@link Collections#synchronizedSet(Set)}. - * - * @param the element type - * @param set the set to synchronize, must not be null - * @return a synchronized set backed by the given set - * @throws NullPointerException if the set is null - */ - public static Set synchronizedSet(final Set set) { - return Collections.synchronizedSet(set); - } - - /** - * Returns an unmodifiable set backed by the given set. - *

- * This method uses the implementation in the decorators subpackage. - * - * @param the element type - * @param set the set to make unmodifiable, must not be null - * @return an unmodifiable set backed by the given set - * @throws NullPointerException if the set is null - */ - public static Set unmodifiableSet(final Set set) { - return UnmodifiableSet.unmodifiableSet(set); - } - - /** - * Returns a predicated (validating) set backed by the given set. - *

- * Only objects that pass the test in the given predicate can be added to the set. - * Trying to add an invalid object results in an IllegalArgumentException. - * It is important not to use the original set after invoking this method, - * as it is a backdoor for adding invalid objects. - * - * @param the element type - * @param set the set to predicate, must not be null - * @param predicate the predicate for the set, must not be null - * @return a predicated set backed by the given set - * @throws NullPointerException if the set or predicate is null - */ - public static Set predicatedSet(final Set set, final Predicate predicate) { - return PredicatedSet.predicatedSet(set, predicate); - } - - /** - * Returns a transformed set backed by the given set. - *

- * Each object is passed through the transformer as it is added to the - * Set. It is important not to use the original set after invoking this - * method, as it is a backdoor for adding untransformed objects. - *

- * Existing entries in the specified set will not be transformed. - * If you want that behaviour, see {@link TransformedSet#transformedSet}. - * - * @param the element type - * @param set the set to transform, must not be null - * @param transformer the transformer for the set, must not be null - * @return a transformed set backed by the given set - * @throws NullPointerException if the set or transformer is null - */ - public static Set transformedSet(final Set set, - final Transformer transformer) { - return TransformedSet.transformingSet(set, transformer); - } - - /** - * Returns a set that maintains the order of elements that are added - * backed by the given set. - *

- * If an element is added twice, the order is determined by the first add. - * The order is observed through the iterator or toArray. - * - * @param the element type - * @param set the set to order, must not be null - * @return an ordered set backed by the given set - * @throws NullPointerException if the set is null - */ - public static Set orderedSet(final Set set) { - return ListOrderedSet.listOrderedSet(set); - } - - // SortedSet - //----------------------------------------------------------------------- - /** - * Returns a synchronized sorted set backed by the given sorted set. - *

- * You must manually synchronize on the returned set's iterator to - * avoid non-deterministic behavior: - * - *

-     * Set s = SetUtils.synchronizedSortedSet(mySet);
-     * synchronized (s) {
-     *     Iterator i = s.iterator();
-     *     while (i.hasNext()) {
-     *         process (i.next());
-     *     }
-     * }
-     * 
- * - * This method is just a wrapper for {@link Collections#synchronizedSortedSet(SortedSet)}. - * - * @param the element type - * @param set the sorted set to synchronize, must not be null - * @return a synchronized set backed by the given set - * @throws NullPointerException if the set is null - */ - public static SortedSet synchronizedSortedSet(final SortedSet set) { - return Collections.synchronizedSortedSet(set); - } - - /** - * Returns an unmodifiable sorted set backed by the given sorted set. - *

- * This method uses the implementation in the decorators subpackage. - * - * @param the element type - * @param set the sorted set to make unmodifiable, must not be null - * @return an unmodifiable set backed by the given set - * @throws NullPointerException if the set is null - */ - public static SortedSet unmodifiableSortedSet(final SortedSet set) { - return UnmodifiableSortedSet.unmodifiableSortedSet(set); - } - - /** - * Returns a predicated (validating) sorted set backed by the given sorted set. - *

- * Only objects that pass the test in the given predicate can be added to the set. - * Trying to add an invalid object results in an IllegalArgumentException. - * It is important not to use the original set after invoking this method, - * as it is a backdoor for adding invalid objects. - * - * @param the element type - * @param set the sorted set to predicate, must not be null - * @param predicate the predicate for the sorted set, must not be null - * @return a predicated sorted set backed by the given sorted set - * @throws NullPointerException if the set or predicate is null - */ - public static SortedSet predicatedSortedSet(final SortedSet set, - final Predicate predicate) { - return PredicatedSortedSet.predicatedSortedSet(set, predicate); - } - - /** - * Returns a transformed sorted set backed by the given set. - *

- * Each object is passed through the transformer as it is added to the - * Set. It is important not to use the original set after invoking this - * method, as it is a backdoor for adding untransformed objects. - *

- * Existing entries in the specified set will not be transformed. - * If you want that behaviour, see {@link TransformedSortedSet#transformedSortedSet}. - * - * @param the element type - * @param set the set to transform, must not be null - * @param transformer the transformer for the set, must not be null - * @return a transformed set backed by the given set - * @throws NullPointerException if the set or transformer is null - */ - public static SortedSet transformedSortedSet(final SortedSet set, - final Transformer transformer) { - return TransformedSortedSet.transformingSortedSet(set, transformer); - } - - // NavigableSet - //----------------------------------------------------------------------- - /** - * Returns an unmodifiable navigable set backed by the given navigable set. - *

- * This method uses the implementation in the decorators subpackage. - * - * @param the element type - * @param set the navigable set to make unmodifiable, must not be null - * @return an unmodifiable set backed by the given set - * @throws NullPointerException if the set is null - * @since 4.1 - */ - public static SortedSet unmodifiableNavigableSet(final NavigableSet set) { - return UnmodifiableNavigableSet.unmodifiableNavigableSet(set); - } - - /** - * Returns a predicated (validating) navigable set backed by the given navigable set. - *

- * Only objects that pass the test in the given predicate can be added to the set. - * Trying to add an invalid object results in an IllegalArgumentException. - * It is important not to use the original set after invoking this method, - * as it is a backdoor for adding invalid objects. - * - * @param the element type - * @param set the navigable set to predicate, must not be null - * @param predicate the predicate for the navigable set, must not be null - * @return a predicated navigable set backed by the given navigable set - * @throws NullPointerException if the set or predicate is null - * @since 4.1 - */ - public static SortedSet predicatedNavigableSet(final NavigableSet set, - final Predicate predicate) { - return PredicatedNavigableSet.predicatedNavigableSet(set, predicate); - } - - /** - * Returns a transformed navigable set backed by the given navigable set. - *

- * Each object is passed through the transformer as it is added to the - * Set. It is important not to use the original set after invoking this - * method, as it is a backdoor for adding untransformed objects. - *

- * Existing entries in the specified set will not be transformed. - * If you want that behaviour, see {@link TransformedNavigableSet#transformedNavigableSet}. - * - * @param the element type - * @param set the navigable set to transform, must not be null - * @param transformer the transformer for the set, must not be null - * @return a transformed set backed by the given set - * @throws NullPointerException if the set or transformer is null - * @since 4.1 - */ - public static SortedSet transformedNavigableSet(final NavigableSet set, - final Transformer transformer) { - return TransformedNavigableSet.transformingNavigableSet(set, transformer); - } - - // Set operations - //----------------------------------------------------------------------- - - /** - * Returns a unmodifiable view of the union of the given {@link Set}s. - *

- * The returned view contains all elements of {@code a} and {@code b}. - * - * @param the generic type that is able to represent the types contained - * in both input sets. - * @param a the first set, must not be null - * @param b the second set, must not be null - * @return a view of the union of the two set - * @throws NullPointerException if either input set is null - * @since 4.1 - */ - public static SetView union(final Set a, final Set b) { - if (a == null || b == null) { - throw new NullPointerException("Sets must not be null."); - } - - final SetView bMinusA = difference(b, a); - - return new SetView() { - @Override - public boolean contains(final Object o) { - return a.contains(o) || b.contains(o); - } - - @Override - public Iterator createIterator() { - return IteratorUtils.chainedIterator(a.iterator(), bMinusA.iterator()); - } - - @Override - public boolean isEmpty() { - return a.isEmpty() && b.isEmpty(); - } - - @Override - public int size() { - return a.size() + bMinusA.size(); - } - }; - } - /** * Returns a unmodifiable view containing the difference of the given * {@link Set}s, denoted by {@code a \ b} (or {@code a - b}). @@ -506,44 +145,6 @@ public class SetUtils { }; } - /** - * Returns a unmodifiable view of the intersection of the given {@link Set}s. - *

- * The returned view contains all elements that are members of both input sets - * ({@code a} and {@code b}). - * - * @param the generic type that is able to represent the types contained - * in both input sets. - * @param a the first set, must not be null - * @param b the second set, must not be null - * @return a view of the intersection of the two sets - * @since 4.1 - */ - public static SetView intersection(final Set a, final Set b) { - if (a == null || b == null) { - throw new NullPointerException("Sets must not be null."); - } - - final Predicate containedInB = new Predicate() { - @Override - public boolean evaluate(final E object) { - return b.contains(object); - } - }; - - return new SetView() { - @Override - public boolean contains(final Object o) { - return a.contains(o) && b.contains(o); - } - - @Override - public Iterator createIterator() { - return IteratorUtils.filteredIterator(a.iterator(), containedInB); - } - }; - } - /** * Returns a unmodifiable view of the symmetric difference of the given * {@link Set}s. @@ -592,53 +193,452 @@ public class SetUtils { } /** - * An unmodifiable view of a set that may be backed by other sets. - *

- * If the decorated sets change, this view will change as well. The contents - * of this view can be transferred to another instance via the {@link #copyInto(Set)} - * and {@link #toSet()} methods. + * Returns an immutable empty set if the argument is null, + * or the argument itself otherwise. * + * @param the element type + * @param set the set, possibly null + * @return an empty set if the argument is null + */ + public static Set emptyIfNull(final Set set) { + return set == null ? Collections.emptySet() : set; + } + + //----------------------------------------------------------------------- + + /** + * Get a typed empty unmodifiable Set. * @param the element type + * @return an empty Set + */ + public static Set emptySet() { + return Collections.emptySet(); + } + + /** + * Get a typed empty unmodifiable sorted set. + * @param the element type + * @return an empty sorted Set + */ + @SuppressWarnings("unchecked") // empty set is OK for any type + public static SortedSet emptySortedSet() { + return EMPTY_SORTED_SET; + } + + /** + * Generates a hash code using the algorithm specified in + * {@link java.util.Set#hashCode()}. + *

+ * This method is useful for implementing Set when you cannot + * extend AbstractSet. The method takes Collection instances to enable other + * collection types to use the Set implementation algorithm. + * + * @param the element type + * @see java.util.Set#hashCode() + * @param set the set to calculate the hash code for, may be null + * @return the hash code + */ + public static int hashCodeForSet(final Collection set) { + if (set == null) { + return 0; + } + + int hashCode = 0; + for (final T obj : set) { + if (obj != null) { + hashCode += obj.hashCode(); + } + } + return hashCode; + } + + /** + * Returns a unmodifiable view of the intersection of the given {@link Set}s. + *

+ * The returned view contains all elements that are members of both input sets + * ({@code a} and {@code b}). + * + * @param the generic type that is able to represent the types contained + * in both input sets. + * @param a the first set, must not be null + * @param b the second set, must not be null + * @return a view of the intersection of the two sets * @since 4.1 */ - public static abstract class SetView extends AbstractSet { - - @Override - public Iterator iterator() { - return IteratorUtils.unmodifiableIterator(createIterator()); + public static SetView intersection(final Set a, final Set b) { + if (a == null || b == null) { + throw new NullPointerException("Sets must not be null."); } - /** - * Return an iterator for this view; the returned iterator is - * not required to be unmodifiable. - * @return a new iterator for this view - */ - protected abstract Iterator createIterator(); + final Predicate containedInB = new Predicate() { + @Override + public boolean evaluate(final E object) { + return b.contains(object); + } + }; - @Override - public int size() { - return IteratorUtils.size(iterator()); - } + return new SetView() { + @Override + public boolean contains(final Object o) { + return a.contains(o) && b.contains(o); + } - /** - * Copies the contents of this view into the provided set. - * - * @param the set type - * @param set the set for copying the contents - */ - public > void copyInto(final S set) { - CollectionUtils.addAll(set, this); - } - - /** - * Returns a new set containing the contents of this view. - * - * @return a new set containing all elements of this view - */ - public Set toSet() { - final Set set = new HashSet<>(size()); - copyInto(set); - return set; - } + @Override + public Iterator createIterator() { + return IteratorUtils.filteredIterator(a.iterator(), containedInB); + } + }; } + + /** + * Tests two sets for equality as per the equals() contract + * in {@link java.util.Set#equals(java.lang.Object)}. + *

+ * This method is useful for implementing Set when you cannot + * extend AbstractSet. The method takes Collection instances to enable other + * collection types to use the Set implementation algorithm. + *

+ * The relevant text (slightly paraphrased as this is a static method) is: + *

+ *

Two sets are considered equal if they have + * the same size, and every member of the first set is contained in + * the second. This ensures that the {@code equals} method works + * properly across different implementations of the {@code Set} + * interface.

+ * + *

+ * This implementation first checks if the two sets are the same object: + * if so it returns {@code true}. Then, it checks if the two sets are + * identical in size; if not, it returns false. If so, it returns + * {@code a.containsAll((Collection) b)}.

+ *
+ * + * @see java.util.Set + * @param set1 the first set, may be null + * @param set2 the second set, may be null + * @return whether the sets are equal by value comparison + */ + public static boolean isEqualSet(final Collection set1, final Collection set2) { + if (set1 == set2) { + return true; + } + if (set1 == null || set2 == null || set1.size() != set2.size()) { + return false; + } + + return set1.containsAll(set2); + } + + /** + * Returns a new hash set that matches elements based on == not + * equals(). + *

+ * This set will violate the detail of various Set contracts. + * As a general rule, don't compare this set to other sets. In particular, you can't + * use decorators like {@link ListOrderedSet} on it, which silently assume that these + * contracts are fulfilled. + *

+ * Note that the returned set is not synchronized and is not thread-safe. + * If you wish to use this set from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedSet(Set)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @param the element type + * @return a new identity hash set + * @since 4.1 + */ + public static Set newIdentityHashSet() { + return Collections.newSetFromMap(new IdentityHashMap()); + } + + /** + * Returns a set that maintains the order of elements that are added + * backed by the given set. + *

+ * If an element is added twice, the order is determined by the first add. + * The order is observed through the iterator or toArray. + * + * @param the element type + * @param set the set to order, must not be null + * @return an ordered set backed by the given set + * @throws NullPointerException if the set is null + */ + public static Set orderedSet(final Set set) { + return ListOrderedSet.listOrderedSet(set); + } + + /** + * Returns a predicated (validating) navigable set backed by the given navigable set. + *

+ * Only objects that pass the test in the given predicate can be added to the set. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original set after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the element type + * @param set the navigable set to predicate, must not be null + * @param predicate the predicate for the navigable set, must not be null + * @return a predicated navigable set backed by the given navigable set + * @throws NullPointerException if the set or predicate is null + * @since 4.1 + */ + public static SortedSet predicatedNavigableSet(final NavigableSet set, + final Predicate predicate) { + return PredicatedNavigableSet.predicatedNavigableSet(set, predicate); + } + + /** + * Returns a predicated (validating) set backed by the given set. + *

+ * Only objects that pass the test in the given predicate can be added to the set. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original set after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the element type + * @param set the set to predicate, must not be null + * @param predicate the predicate for the set, must not be null + * @return a predicated set backed by the given set + * @throws NullPointerException if the set or predicate is null + */ + public static Set predicatedSet(final Set set, final Predicate predicate) { + return PredicatedSet.predicatedSet(set, predicate); + } + + /** + * Returns a predicated (validating) sorted set backed by the given sorted set. + *

+ * Only objects that pass the test in the given predicate can be added to the set. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original set after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the element type + * @param set the sorted set to predicate, must not be null + * @param predicate the predicate for the sorted set, must not be null + * @return a predicated sorted set backed by the given sorted set + * @throws NullPointerException if the set or predicate is null + */ + public static SortedSet predicatedSortedSet(final SortedSet set, + final Predicate predicate) { + return PredicatedSortedSet.predicatedSortedSet(set, predicate); + } + + // Set + //----------------------------------------------------------------------- + /** + * Returns a synchronized set backed by the given set. + *

+ * You must manually synchronize on the returned set's iterator to + * avoid non-deterministic behavior: + * + *

+     * Set s = SetUtils.synchronizedSet(mySet);
+     * synchronized (s) {
+     *     Iterator i = s.iterator();
+     *     while (i.hasNext()) {
+     *         process (i.next());
+     *     }
+     * }
+     * 
+ * + * This method is just a wrapper for {@link Collections#synchronizedSet(Set)}. + * + * @param the element type + * @param set the set to synchronize, must not be null + * @return a synchronized set backed by the given set + * @throws NullPointerException if the set is null + */ + public static Set synchronizedSet(final Set set) { + return Collections.synchronizedSet(set); + } + + // SortedSet + //----------------------------------------------------------------------- + /** + * Returns a synchronized sorted set backed by the given sorted set. + *

+ * You must manually synchronize on the returned set's iterator to + * avoid non-deterministic behavior: + * + *

+     * Set s = SetUtils.synchronizedSortedSet(mySet);
+     * synchronized (s) {
+     *     Iterator i = s.iterator();
+     *     while (i.hasNext()) {
+     *         process (i.next());
+     *     }
+     * }
+     * 
+ * + * This method is just a wrapper for {@link Collections#synchronizedSortedSet(SortedSet)}. + * + * @param the element type + * @param set the sorted set to synchronize, must not be null + * @return a synchronized set backed by the given set + * @throws NullPointerException if the set is null + */ + public static SortedSet synchronizedSortedSet(final SortedSet set) { + return Collections.synchronizedSortedSet(set); + } + + /** + * Returns a transformed navigable set backed by the given navigable set. + *

+ * Each object is passed through the transformer as it is added to the + * Set. It is important not to use the original set after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

+ * Existing entries in the specified set will not be transformed. + * If you want that behaviour, see {@link TransformedNavigableSet#transformedNavigableSet}. + * + * @param the element type + * @param set the navigable set to transform, must not be null + * @param transformer the transformer for the set, must not be null + * @return a transformed set backed by the given set + * @throws NullPointerException if the set or transformer is null + * @since 4.1 + */ + public static SortedSet transformedNavigableSet(final NavigableSet set, + final Transformer transformer) { + return TransformedNavigableSet.transformingNavigableSet(set, transformer); + } + + /** + * Returns a transformed set backed by the given set. + *

+ * Each object is passed through the transformer as it is added to the + * Set. It is important not to use the original set after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

+ * Existing entries in the specified set will not be transformed. + * If you want that behaviour, see {@link TransformedSet#transformedSet}. + * + * @param the element type + * @param set the set to transform, must not be null + * @param transformer the transformer for the set, must not be null + * @return a transformed set backed by the given set + * @throws NullPointerException if the set or transformer is null + */ + public static Set transformedSet(final Set set, + final Transformer transformer) { + return TransformedSet.transformingSet(set, transformer); + } + + /** + * Returns a transformed sorted set backed by the given set. + *

+ * Each object is passed through the transformer as it is added to the + * Set. It is important not to use the original set after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

+ * Existing entries in the specified set will not be transformed. + * If you want that behaviour, see {@link TransformedSortedSet#transformedSortedSet}. + * + * @param the element type + * @param set the set to transform, must not be null + * @param transformer the transformer for the set, must not be null + * @return a transformed set backed by the given set + * @throws NullPointerException if the set or transformer is null + */ + public static SortedSet transformedSortedSet(final SortedSet set, + final Transformer transformer) { + return TransformedSortedSet.transformingSortedSet(set, transformer); + } + + /** + * Returns a unmodifiable view of the union of the given {@link Set}s. + *

+ * The returned view contains all elements of {@code a} and {@code b}. + * + * @param the generic type that is able to represent the types contained + * in both input sets. + * @param a the first set, must not be null + * @param b the second set, must not be null + * @return a view of the union of the two set + * @throws NullPointerException if either input set is null + * @since 4.1 + */ + public static SetView union(final Set a, final Set b) { + if (a == null || b == null) { + throw new NullPointerException("Sets must not be null."); + } + + final SetView bMinusA = difference(b, a); + + return new SetView() { + @Override + public boolean contains(final Object o) { + return a.contains(o) || b.contains(o); + } + + @Override + public Iterator createIterator() { + return IteratorUtils.chainedIterator(a.iterator(), bMinusA.iterator()); + } + + @Override + public boolean isEmpty() { + return a.isEmpty() && b.isEmpty(); + } + + @Override + public int size() { + return a.size() + bMinusA.size(); + } + }; + } + + // Set operations + //----------------------------------------------------------------------- + + // NavigableSet + //----------------------------------------------------------------------- + /** + * Returns an unmodifiable navigable set backed by the given navigable set. + *

+ * This method uses the implementation in the decorators subpackage. + * + * @param the element type + * @param set the navigable set to make unmodifiable, must not be null + * @return an unmodifiable set backed by the given set + * @throws NullPointerException if the set is null + * @since 4.1 + */ + public static SortedSet unmodifiableNavigableSet(final NavigableSet set) { + return UnmodifiableNavigableSet.unmodifiableNavigableSet(set); + } + + /** + * Returns an unmodifiable set backed by the given set. + *

+ * This method uses the implementation in the decorators subpackage. + * + * @param the element type + * @param set the set to make unmodifiable, must not be null + * @return an unmodifiable set backed by the given set + * @throws NullPointerException if the set is null + */ + public static Set unmodifiableSet(final Set set) { + return UnmodifiableSet.unmodifiableSet(set); + } + + /** + * Create an unmodifiable set from the given items. If the passed var-args argument is {@code + * null}, then the method returns {@code null}. + * @param the element type + * @return a set + */ + public static Set unmodifiableSetSet(final E... items) { + if (items == null) { + return null; + } + return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(items))); + } + + /** + * SetUtils should not normally be instantiated. + */ + private SetUtils() {} }