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