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 }