View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections;
18  
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.Set;
22  import java.util.SortedSet;
23  import java.util.TreeSet;
24  
25  import org.apache.commons.collections.set.ListOrderedSet;
26  import org.apache.commons.collections.set.PredicatedSet;
27  import org.apache.commons.collections.set.PredicatedSortedSet;
28  import org.apache.commons.collections.set.SynchronizedSet;
29  import org.apache.commons.collections.set.SynchronizedSortedSet;
30  import org.apache.commons.collections.set.TransformedSet;
31  import org.apache.commons.collections.set.TransformedSortedSet;
32  import org.apache.commons.collections.set.UnmodifiableSet;
33  import org.apache.commons.collections.set.UnmodifiableSortedSet;
34  
35  /**
36   * Provides utility methods and decorators for
37   * {@link Set} and {@link SortedSet} instances.
38   *
39   * @since 2.1
40   * @version $Id: SetUtils.java 1436066 2013-01-21 01:28:08Z sebb $
41   */
42  public class SetUtils {
43  
44      /**
45       * An empty unmodifiable set.
46       * This uses the {@link Collections} implementation 
47       * and is provided for completeness.
48       */
49      public static final Set<?> EMPTY_SET = Collections.EMPTY_SET;
50  
51      /**
52       * Get a typed empty unmodifiable Set.
53       * @param <E> the element type
54       * @return an empty Set
55       */
56      public static <E> Set<E> emptySet() {
57          return Collections.<E>emptySet();
58      }
59  
60      /**
61       * An empty unmodifiable sorted set.
62       * This is not provided in the JDK.
63       */
64      public static final SortedSet<?> EMPTY_SORTED_SET =
65              UnmodifiableSortedSet.unmodifiableSortedSet(new TreeSet<Object>());
66  
67      /**
68       * Get a typed empty unmodifiable sorted set.
69       * @param <E> the element type
70       * @return an empty sorted Set
71       */
72      @SuppressWarnings("unchecked") // empty set is OK for any type
73      public static <E> SortedSet<E> emptySortedSet() {
74          return (SortedSet<E>) EMPTY_SORTED_SET;
75      }
76  
77      /**
78       * <code>SetUtils</code> should not normally be instantiated.
79       */
80      public SetUtils() {
81      }
82  
83      //-----------------------------------------------------------------------
84      
85      /**
86       * Returns an immutable empty set if the argument is <code>null</code>,
87       * or the argument itself otherwise.
88       * 
89       * @param <T> the element type
90       * @param set the set, possibly <code>null</code>
91       * @return an empty set if the argument is <code>null</code>
92       */
93      public static <T> Set<T> emptyIfNull(final Set<T> set) {
94          return set == null ? Collections.<T>emptySet() : set;
95      }
96      
97      /**
98       * Tests two sets for equality as per the <code>equals()</code> contract
99       * in {@link java.util.Set#equals(java.lang.Object)}.
100      * <p>
101      * This method is useful for implementing <code>Set</code> when you cannot
102      * extend AbstractSet. The method takes Collection instances to enable other
103      * collection types to use the Set implementation algorithm.
104      * <p>
105      * The relevant text (slightly paraphrased as this is a static method) is:
106      * <blockquote>
107      * <p>Two sets are considered equal if they have
108      * the same size, and every member of the first set is contained in
109      * the second. This ensures that the <tt>equals</tt> method works
110      * properly across different implementations of the <tt>Set</tt>
111      * interface.</p>
112      * 
113      * <p>
114      * This implementation first checks if the two sets are the same object: 
115      * if so it returns <tt>true</tt>.  Then, it checks if the two sets are
116      * identical in size; if not, it returns false. If so, it returns
117      * <tt>a.containsAll((Collection) b)</tt>.</p>
118      * </blockquote>
119      * 
120      * @see java.util.Set
121      * @param set1  the first set, may be null
122      * @param set2  the second set, may be null
123      * @return whether the sets are equal by value comparison
124      */
125     public static boolean isEqualSet(final Collection<?> set1, final Collection<?> set2) {
126         if (set1 == set2) {
127             return true;
128         }
129         if (set1 == null || set2 == null || set1.size() != set2.size()) {
130             return false;
131         }
132 
133         return set1.containsAll(set2);
134     }
135 
136     /**
137      * Generates a hash code using the algorithm specified in 
138      * {@link java.util.Set#hashCode()}.
139      * <p>
140      * This method is useful for implementing <code>Set</code> when you cannot
141      * extend AbstractSet. The method takes Collection instances to enable other
142      * collection types to use the Set implementation algorithm.
143      * 
144      * @param <T> the element type
145      * @see java.util.Set#hashCode()
146      * @param set  the set to calculate the hash code for, may be null
147      * @return the hash code
148      */
149     public static <T> int hashCodeForSet(final Collection<T> set) {
150         if (set == null) {
151             return 0;
152         }
153 
154         int hashCode = 0;
155         for (final T obj : set) {
156             if (obj != null) {
157                 hashCode += obj.hashCode();
158             }
159         }
160         return hashCode;
161     }
162     
163     //-----------------------------------------------------------------------
164     /**
165      * Returns a synchronized set backed by the given set.
166      * <p>
167      * You must manually synchronize on the returned buffer's iterator to 
168      * avoid non-deterministic behavior:
169      *  
170      * <pre>
171      * Set s = SetUtils.synchronizedSet(mySet);
172      * synchronized (s) {
173      *     Iterator i = s.iterator();
174      *     while (i.hasNext()) {
175      *         process (i.next());
176      *     }
177      * }
178      * </pre>
179      * 
180      * This method uses the implementation in the decorators subpackage.
181      * 
182      * @param <E> the element type
183      * @param set  the set to synchronize, must not be null
184      * @return a synchronized set backed by the given set
185      * @throws IllegalArgumentException  if the set is null
186      */
187     public static <E> Set<E> synchronizedSet(final Set<E> set) {
188         return SynchronizedSet.synchronizedSet(set);
189     }
190 
191     /**
192      * Returns an unmodifiable set backed by the given set.
193      * <p>
194      * This method uses the implementation in the decorators subpackage.
195      *
196      * @param <E> the element type
197      * @param set  the set to make unmodifiable, must not be null
198      * @return an unmodifiable set backed by the given set
199      * @throws IllegalArgumentException  if the set is null
200      */
201     public static <E> Set<E> unmodifiableSet(final Set<E> set) {
202         return UnmodifiableSet.unmodifiableSet(set);
203     }
204 
205     /**
206      * Returns a predicated (validating) set backed by the given set.
207      * <p>
208      * Only objects that pass the test in the given predicate can be added to the set.
209      * Trying to add an invalid object results in an IllegalArgumentException.
210      * It is important not to use the original set after invoking this method,
211      * as it is a backdoor for adding invalid objects.
212      *
213      * @param <E> the element type
214      * @param set  the set to predicate, must not be null
215      * @param predicate  the predicate for the set, must not be null
216      * @return a predicated set backed by the given set
217      * @throws IllegalArgumentException  if the Set or Predicate is null
218      */
219     public static <E> Set<E> predicatedSet(final Set<E> set, final Predicate<? super E> predicate) {
220         return PredicatedSet.predicatedSet(set, predicate);
221     }
222 
223     /**
224      * Returns a transformed set backed by the given set.
225      * <p>
226      * Each object is passed through the transformer as it is added to the
227      * Set. It is important not to use the original set after invoking this 
228      * method, as it is a backdoor for adding untransformed objects.
229      * <p>
230      * Existing entries in the specified set will not be transformed.
231      * If you want that behaviour, see {@link TransformedSet#transformedSet}.
232      *
233      * @param <E> the element type
234      * @param set  the set to transform, must not be null
235      * @param transformer  the transformer for the set, must not be null
236      * @return a transformed set backed by the given set
237      * @throws IllegalArgumentException  if the Set or Transformer is null
238      */
239     public static <E> Set<E> transformedSet(final Set<E> set, final Transformer<? super E, ? extends E> transformer) {
240         return TransformedSet.transformingSet(set, transformer);
241     }
242     
243     /**
244      * Returns a set that maintains the order of elements that are added
245      * backed by the given set.
246      * <p>
247      * If an element is added twice, the order is determined by the first add.
248      * The order is observed through the iterator or toArray.
249      *
250      * @param <E> the element type
251      * @param set  the set to order, must not be null
252      * @return an ordered set backed by the given set
253      * @throws IllegalArgumentException  if the Set is null
254      */
255     public static <E> Set<E> orderedSet(final Set<E> set) {
256         return ListOrderedSet.listOrderedSet(set);
257     }
258     
259     //-----------------------------------------------------------------------
260     /**
261      * Returns a synchronized sorted set backed by the given sorted set.
262      * <p>
263      * You must manually synchronize on the returned buffer's iterator to 
264      * avoid non-deterministic behavior:
265      *  
266      * <pre>
267      * Set s = SetUtils.synchronizedSet(mySet);
268      * synchronized (s) {
269      *     Iterator i = s.iterator();
270      *     while (i.hasNext()) {
271      *         process (i.next());
272      *     }
273      * }
274      * </pre>
275      * 
276      * This method uses the implementation in the decorators subpackage.
277      * 
278      * @param <E> the element type
279      * @param set  the sorted set to synchronize, must not be null
280      * @return a synchronized set backed by the given set
281      * @throws IllegalArgumentException  if the set is null
282      */
283     public static <E> SortedSet<E> synchronizedSortedSet(final SortedSet<E> set) {
284         return SynchronizedSortedSet.synchronizedSortedSet(set);
285     }
286 
287     /**
288      * Returns an unmodifiable sorted set backed by the given sorted set.
289      * <p>
290      * This method uses the implementation in the decorators subpackage.
291      *
292      * @param <E> the element type
293      * @param set  the sorted set to make unmodifiable, must not be null
294      * @return an unmodifiable set backed by the given set
295      * @throws IllegalArgumentException  if the set is null
296      */
297     public static <E> SortedSet<E> unmodifiableSortedSet(final SortedSet<E> set) {
298         return UnmodifiableSortedSet.unmodifiableSortedSet(set);
299     }
300 
301     /**
302      * Returns a predicated (validating) sorted set backed by the given sorted set.  
303      * <p>
304      * Only objects that pass the test in the given predicate can be added to the set.
305      * Trying to add an invalid object results in an IllegalArgumentException.
306      * It is important not to use the original set after invoking this method,
307      * as it is a backdoor for adding invalid objects.
308      *
309      * @param <E> the element type
310      * @param set  the sorted set to predicate, must not be null
311      * @param predicate  the predicate for the sorted set, must not be null
312      * @return a predicated sorted set backed by the given sorted set
313      * @throws IllegalArgumentException  if the Set or Predicate is null
314      */
315     public static <E> SortedSet<E> predicatedSortedSet(final SortedSet<E> set, final Predicate<? super E> predicate) {
316         return PredicatedSortedSet.predicatedSortedSet(set, predicate);
317     }
318 
319     /**
320      * Returns a transformed sorted set backed by the given set.
321      * <p>
322      * Each object is passed through the transformer as it is added to the
323      * Set. It is important not to use the original set after invoking this 
324      * method, as it is a backdoor for adding untransformed objects.
325      * <p>
326      * Existing entries in the specified set will not be transformed.
327      * If you want that behaviour, see {@link TransformedSortedSet#transformedSortedSet}.
328      *
329      * @param <E> the element type
330      * @param set  the set to transform, must not be null
331      * @param transformer  the transformer for the set, must not be null
332      * @return a transformed set backed by the given set
333      * @throws IllegalArgumentException  if the Set or Transformer is null
334      */
335     public static <E> SortedSet<E> transformedSortedSet(final SortedSet<E> set,
336                                                         final Transformer<? super E, ? extends E> transformer) {
337         return TransformedSortedSet.transformingSortedSet(set, transformer);
338     }
339     
340 }