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 }