001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.collections;
018
019 import java.util.Collection;
020 import java.util.Collections;
021 import java.util.Iterator;
022 import java.util.Set;
023 import java.util.SortedSet;
024 import java.util.TreeSet;
025
026 import org.apache.commons.collections.set.ListOrderedSet;
027 import org.apache.commons.collections.set.PredicatedSet;
028 import org.apache.commons.collections.set.PredicatedSortedSet;
029 import org.apache.commons.collections.set.SynchronizedSet;
030 import org.apache.commons.collections.set.SynchronizedSortedSet;
031 import org.apache.commons.collections.set.TransformedSet;
032 import org.apache.commons.collections.set.TransformedSortedSet;
033 import org.apache.commons.collections.set.TypedSet;
034 import org.apache.commons.collections.set.TypedSortedSet;
035 import org.apache.commons.collections.set.UnmodifiableSet;
036 import org.apache.commons.collections.set.UnmodifiableSortedSet;
037
038 /**
039 * Provides utility methods and decorators for
040 * {@link Set} and {@link SortedSet} instances.
041 *
042 * @since Commons Collections 2.1
043 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
044 *
045 * @author Paul Jack
046 * @author Stephen Colebourne
047 * @author Neil O'Toole
048 * @author Matthew Hawthorne
049 */
050 public class SetUtils {
051
052 /**
053 * An empty unmodifiable set.
054 * This uses the {@link Collections} implementation
055 * and is provided for completeness.
056 */
057 public static final Set EMPTY_SET = Collections.EMPTY_SET;
058 /**
059 * An empty unmodifiable sorted set.
060 * This is not provided in the JDK.
061 */
062 public static final SortedSet EMPTY_SORTED_SET = UnmodifiableSortedSet.decorate(new TreeSet());
063
064 /**
065 * <code>SetUtils</code> should not normally be instantiated.
066 */
067 public SetUtils() {
068 }
069
070 //-----------------------------------------------------------------------
071 /**
072 * Tests two sets for equality as per the <code>equals()</code> contract
073 * in {@link java.util.Set#equals(java.lang.Object)}.
074 * <p>
075 * This method is useful for implementing <code>Set</code> when you cannot
076 * extend AbstractSet. The method takes Collection instances to enable other
077 * collection types to use the Set implementation algorithm.
078 * <p>
079 * The relevant text (slightly paraphrased as this is a static method) is:
080 * <blockquote>
081 * <p>Two sets are considered equal if they have
082 * the same size, and every member of the first set is contained in
083 * the second. This ensures that the <tt>equals</tt> method works
084 * properly across different implementations of the <tt>Set</tt>
085 * interface.</p>
086 *
087 * <p>
088 * This implementation first checks if the two sets are the same object:
089 * if so it returns <tt>true</tt>. Then, it checks if the two sets are
090 * identical in size; if not, it returns false. If so, it returns
091 * <tt>a.containsAll((Collection) b)</tt>.</p>
092 * </blockquote>
093 *
094 * @see java.util.Set
095 * @param set1 the first set, may be null
096 * @param set2 the second set, may be null
097 * @return whether the sets are equal by value comparison
098 */
099 public static boolean isEqualSet(final Collection set1, final Collection set2) {
100 if (set1 == set2) {
101 return true;
102 }
103 if (set1 == null || set2 == null || set1.size() != set2.size()) {
104 return false;
105 }
106
107 return set1.containsAll(set2);
108 }
109
110 /**
111 * Generates a hash code using the algorithm specified in
112 * {@link java.util.Set#hashCode()}.
113 * <p>
114 * This method is useful for implementing <code>Set</code> when you cannot
115 * extend AbstractSet. The method takes Collection instances to enable other
116 * collection types to use the Set implementation algorithm.
117 *
118 * @see java.util.Set#hashCode()
119 * @param set the set to calculate the hash code for, may be null
120 * @return the hash code
121 */
122 public static int hashCodeForSet(final Collection set) {
123 if (set == null) {
124 return 0;
125 }
126 int hashCode = 0;
127 Iterator it = set.iterator();
128 Object obj = null;
129
130 while (it.hasNext()) {
131 obj = it.next();
132 if (obj != null) {
133 hashCode += obj.hashCode();
134 }
135 }
136 return hashCode;
137 }
138
139 //-----------------------------------------------------------------------
140 /**
141 * Returns a synchronized set backed by the given set.
142 * <p>
143 * You must manually synchronize on the returned buffer's iterator to
144 * avoid non-deterministic behavior:
145 *
146 * <pre>
147 * Set s = SetUtils.synchronizedSet(mySet);
148 * synchronized (s) {
149 * Iterator i = s.iterator();
150 * while (i.hasNext()) {
151 * process (i.next());
152 * }
153 * }
154 * </pre>
155 *
156 * This method uses the implementation in the decorators subpackage.
157 *
158 * @param set the set to synchronize, must not be null
159 * @return a synchronized set backed by the given set
160 * @throws IllegalArgumentException if the set is null
161 */
162 public static Set synchronizedSet(Set set) {
163 return SynchronizedSet.decorate(set);
164 }
165
166 /**
167 * Returns an unmodifiable set backed by the given set.
168 * <p>
169 * This method uses the implementation in the decorators subpackage.
170 *
171 * @param set the set to make unmodifiable, must not be null
172 * @return an unmodifiable set backed by the given set
173 * @throws IllegalArgumentException if the set is null
174 */
175 public static Set unmodifiableSet(Set set) {
176 return UnmodifiableSet.decorate(set);
177 }
178
179 /**
180 * Returns a predicated (validating) set backed by the given set.
181 * <p>
182 * Only objects that pass the test in the given predicate can be added to the set.
183 * Trying to add an invalid object results in an IllegalArgumentException.
184 * It is important not to use the original set after invoking this method,
185 * as it is a backdoor for adding invalid objects.
186 *
187 * @param set the set to predicate, must not be null
188 * @param predicate the predicate for the set, must not be null
189 * @return a predicated set backed by the given set
190 * @throws IllegalArgumentException if the Set or Predicate is null
191 */
192 public static Set predicatedSet(Set set, Predicate predicate) {
193 return PredicatedSet.decorate(set, predicate);
194 }
195
196 /**
197 * Returns a typed set backed by the given set.
198 * <p>
199 * Only objects of the specified type can be added to the set.
200 *
201 * @param set the set to limit to a specific type, must not be null
202 * @param type the type of objects which may be added to the set
203 * @return a typed set backed by the specified set
204 */
205 public static Set typedSet(Set set, Class type) {
206 return TypedSet.decorate(set, type);
207 }
208
209 /**
210 * Returns a transformed set backed by the given set.
211 * <p>
212 * Each object is passed through the transformer as it is added to the
213 * Set. It is important not to use the original set after invoking this
214 * method, as it is a backdoor for adding untransformed objects.
215 *
216 * @param set the set to transform, must not be null
217 * @param transformer the transformer for the set, must not be null
218 * @return a transformed set backed by the given set
219 * @throws IllegalArgumentException if the Set or Transformer is null
220 */
221 public static Set transformedSet(Set set, Transformer transformer) {
222 return TransformedSet.decorate(set, transformer);
223 }
224
225 /**
226 * Returns a set that maintains the order of elements that are added
227 * backed by the given set.
228 * <p>
229 * If an element is added twice, the order is determined by the first add.
230 * The order is observed through the iterator or toArray.
231 *
232 * @param set the set to order, must not be null
233 * @return an ordered set backed by the given set
234 * @throws IllegalArgumentException if the Set is null
235 */
236 public static Set orderedSet(Set set) {
237 return ListOrderedSet.decorate(set);
238 }
239
240 //-----------------------------------------------------------------------
241 /**
242 * Returns a synchronized sorted set backed by the given sorted set.
243 * <p>
244 * You must manually synchronize on the returned buffer's iterator to
245 * avoid non-deterministic behavior:
246 *
247 * <pre>
248 * Set s = SetUtils.synchronizedSet(mySet);
249 * synchronized (s) {
250 * Iterator i = s.iterator();
251 * while (i.hasNext()) {
252 * process (i.next());
253 * }
254 * }
255 * </pre>
256 *
257 * This method uses the implementation in the decorators subpackage.
258 *
259 * @param set the sorted set to synchronize, must not be null
260 * @return a synchronized set backed by the given set
261 * @throws IllegalArgumentException if the set is null
262 */
263 public static SortedSet synchronizedSortedSet(SortedSet set) {
264 return SynchronizedSortedSet.decorate(set);
265 }
266
267 /**
268 * Returns an unmodifiable sorted set backed by the given sorted set.
269 * <p>
270 * This method uses the implementation in the decorators subpackage.
271 *
272 * @param set the sorted set to make unmodifiable, must not be null
273 * @return an unmodifiable set backed by the given set
274 * @throws IllegalArgumentException if the set is null
275 */
276 public static SortedSet unmodifiableSortedSet(SortedSet set) {
277 return UnmodifiableSortedSet.decorate(set);
278 }
279
280 /**
281 * Returns a predicated (validating) sorted set backed by the given sorted set.
282 * <p>
283 * Only objects that pass the test in the given predicate can be added to the set.
284 * Trying to add an invalid object results in an IllegalArgumentException.
285 * It is important not to use the original set after invoking this method,
286 * as it is a backdoor for adding invalid objects.
287 *
288 * @param set the sorted set to predicate, must not be null
289 * @param predicate the predicate for the sorted set, must not be null
290 * @return a predicated sorted set backed by the given sorted set
291 * @throws IllegalArgumentException if the Set or Predicate is null
292 */
293 public static SortedSet predicatedSortedSet(SortedSet set, Predicate predicate) {
294 return PredicatedSortedSet.decorate(set, predicate);
295 }
296
297 /**
298 * Returns a typed sorted set backed by the given set.
299 * <p>
300 * Only objects of the specified type can be added to the set.
301 *
302 * @param set the set to limit to a specific type, must not be null
303 * @param type the type of objects which may be added to the set
304 * @return a typed set backed by the specified set
305 */
306 public static SortedSet typedSortedSet(SortedSet set, Class type) {
307 return TypedSortedSet.decorate(set, type);
308 }
309
310 /**
311 * Returns a transformed sorted set backed by the given set.
312 * <p>
313 * Each object is passed through the transformer as it is added to the
314 * Set. It is important not to use the original set after invoking this
315 * method, as it is a backdoor for adding untransformed objects.
316 *
317 * @param set the set to transform, must not be null
318 * @param transformer the transformer for the set, must not be null
319 * @return a transformed set backed by the given set
320 * @throws IllegalArgumentException if the Set or Transformer is null
321 */
322 public static SortedSet transformedSortedSet(SortedSet set, Transformer transformer) {
323 return TransformedSortedSet.decorate(set, transformer);
324 }
325
326 }