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 */ 017package org.apache.commons.collections4; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.Set; 022import java.util.SortedSet; 023import java.util.TreeSet; 024 025import org.apache.commons.collections4.set.ListOrderedSet; 026import org.apache.commons.collections4.set.PredicatedSet; 027import org.apache.commons.collections4.set.PredicatedSortedSet; 028import org.apache.commons.collections4.set.TransformedSet; 029import org.apache.commons.collections4.set.TransformedSortedSet; 030import org.apache.commons.collections4.set.UnmodifiableSet; 031import org.apache.commons.collections4.set.UnmodifiableSortedSet; 032 033/** 034 * Provides utility methods and decorators for 035 * {@link Set} and {@link SortedSet} instances. 036 * 037 * @since 2.1 038 * @version $Id: SetUtils.html 972421 2015-11-14 20:00:04Z tn $ 039 */ 040public class SetUtils { 041 042 /** 043 * Get a typed empty unmodifiable Set. 044 * @param <E> the element type 045 * @return an empty Set 046 */ 047 public static <E> Set<E> emptySet() { 048 return Collections.<E>emptySet(); 049 } 050 051 /** 052 * An empty unmodifiable sorted set. 053 * This is not provided in the JDK. 054 */ 055 @SuppressWarnings("rawtypes") 056 public static final SortedSet EMPTY_SORTED_SET = 057 UnmodifiableSortedSet.unmodifiableSortedSet(new TreeSet<Object>()); 058 059 /** 060 * Get a typed empty unmodifiable sorted set. 061 * @param <E> the element type 062 * @return an empty sorted Set 063 */ 064 @SuppressWarnings("unchecked") // empty set is OK for any type 065 public static <E> SortedSet<E> emptySortedSet() { 066 return (SortedSet<E>) EMPTY_SORTED_SET; 067 } 068 069 /** 070 * <code>SetUtils</code> should not normally be instantiated. 071 */ 072 private SetUtils() {} 073 074 //----------------------------------------------------------------------- 075 076 /** 077 * Returns an immutable empty set if the argument is <code>null</code>, 078 * or the argument itself otherwise. 079 * 080 * @param <T> the element type 081 * @param set the set, possibly <code>null</code> 082 * @return an empty set if the argument is <code>null</code> 083 */ 084 public static <T> Set<T> emptyIfNull(final Set<T> set) { 085 return set == null ? Collections.<T>emptySet() : set; 086 } 087 088 /** 089 * Tests two sets for equality as per the <code>equals()</code> contract 090 * in {@link java.util.Set#equals(java.lang.Object)}. 091 * <p> 092 * This method is useful for implementing <code>Set</code> when you cannot 093 * extend AbstractSet. The method takes Collection instances to enable other 094 * collection types to use the Set implementation algorithm. 095 * <p> 096 * The relevant text (slightly paraphrased as this is a static method) is: 097 * <blockquote> 098 * <p>Two sets are considered equal if they have 099 * the same size, and every member of the first set is contained in 100 * the second. This ensures that the <tt>equals</tt> method works 101 * properly across different implementations of the <tt>Set</tt> 102 * interface.</p> 103 * 104 * <p> 105 * This implementation first checks if the two sets are the same object: 106 * if so it returns <tt>true</tt>. Then, it checks if the two sets are 107 * identical in size; if not, it returns false. If so, it returns 108 * <tt>a.containsAll((Collection) b)</tt>.</p> 109 * </blockquote> 110 * 111 * @see java.util.Set 112 * @param set1 the first set, may be null 113 * @param set2 the second set, may be null 114 * @return whether the sets are equal by value comparison 115 */ 116 public static boolean isEqualSet(final Collection<?> set1, final Collection<?> set2) { 117 if (set1 == set2) { 118 return true; 119 } 120 if (set1 == null || set2 == null || set1.size() != set2.size()) { 121 return false; 122 } 123 124 return set1.containsAll(set2); 125 } 126 127 /** 128 * Generates a hash code using the algorithm specified in 129 * {@link java.util.Set#hashCode()}. 130 * <p> 131 * This method is useful for implementing <code>Set</code> when you cannot 132 * extend AbstractSet. The method takes Collection instances to enable other 133 * collection types to use the Set implementation algorithm. 134 * 135 * @param <T> the element type 136 * @see java.util.Set#hashCode() 137 * @param set the set to calculate the hash code for, may be null 138 * @return the hash code 139 */ 140 public static <T> int hashCodeForSet(final Collection<T> set) { 141 if (set == null) { 142 return 0; 143 } 144 145 int hashCode = 0; 146 for (final T obj : set) { 147 if (obj != null) { 148 hashCode += obj.hashCode(); 149 } 150 } 151 return hashCode; 152 } 153 154 //----------------------------------------------------------------------- 155 /** 156 * Returns a synchronized set backed by the given set. 157 * <p> 158 * You must manually synchronize on the returned set's iterator to 159 * avoid non-deterministic behavior: 160 * 161 * <pre> 162 * Set s = SetUtils.synchronizedSet(mySet); 163 * synchronized (s) { 164 * Iterator i = s.iterator(); 165 * while (i.hasNext()) { 166 * process (i.next()); 167 * } 168 * } 169 * </pre> 170 * 171 * This method is just a wrapper for {@link Collections#synchronizedSet(Set)}. 172 * 173 * @param <E> the element type 174 * @param set the set to synchronize, must not be null 175 * @return a synchronized set backed by the given set 176 * @throws IllegalArgumentException if the set is null 177 */ 178 public static <E> Set<E> synchronizedSet(final Set<E> set) { 179 return Collections.synchronizedSet(set); 180 } 181 182 /** 183 * Returns an unmodifiable set backed by the given set. 184 * <p> 185 * This method uses the implementation in the decorators subpackage. 186 * 187 * @param <E> the element type 188 * @param set the set to make unmodifiable, must not be null 189 * @return an unmodifiable set backed by the given set 190 * @throws IllegalArgumentException if the set is null 191 */ 192 public static <E> Set<E> unmodifiableSet(final Set<? extends E> set) { 193 return UnmodifiableSet.unmodifiableSet(set); 194 } 195 196 /** 197 * Returns a predicated (validating) set backed by the given set. 198 * <p> 199 * Only objects that pass the test in the given predicate can be added to the set. 200 * Trying to add an invalid object results in an IllegalArgumentException. 201 * It is important not to use the original set after invoking this method, 202 * as it is a backdoor for adding invalid objects. 203 * 204 * @param <E> the element type 205 * @param set the set to predicate, must not be null 206 * @param predicate the predicate for the set, must not be null 207 * @return a predicated set backed by the given set 208 * @throws IllegalArgumentException if the Set or Predicate is null 209 */ 210 public static <E> Set<E> predicatedSet(final Set<E> set, final Predicate<? super E> predicate) { 211 return PredicatedSet.predicatedSet(set, predicate); 212 } 213 214 /** 215 * Returns a transformed set backed by the given set. 216 * <p> 217 * Each object is passed through the transformer as it is added to the 218 * Set. It is important not to use the original set after invoking this 219 * method, as it is a backdoor for adding untransformed objects. 220 * <p> 221 * Existing entries in the specified set will not be transformed. 222 * If you want that behaviour, see {@link TransformedSet#transformedSet}. 223 * 224 * @param <E> the element type 225 * @param set the set to transform, must not be null 226 * @param transformer the transformer for the set, must not be null 227 * @return a transformed set backed by the given set 228 * @throws IllegalArgumentException if the Set or Transformer is null 229 */ 230 public static <E> Set<E> transformedSet(final Set<E> set, final Transformer<? super E, ? extends E> transformer) { 231 return TransformedSet.transformingSet(set, transformer); 232 } 233 234 /** 235 * Returns a set that maintains the order of elements that are added 236 * backed by the given set. 237 * <p> 238 * If an element is added twice, the order is determined by the first add. 239 * The order is observed through the iterator or toArray. 240 * 241 * @param <E> the element type 242 * @param set the set to order, must not be null 243 * @return an ordered set backed by the given set 244 * @throws IllegalArgumentException if the Set is null 245 */ 246 public static <E> Set<E> orderedSet(final Set<E> set) { 247 return ListOrderedSet.listOrderedSet(set); 248 } 249 250 //----------------------------------------------------------------------- 251 /** 252 * Returns a synchronized sorted set backed by the given sorted set. 253 * <p> 254 * You must manually synchronize on the returned set's iterator to 255 * avoid non-deterministic behavior: 256 * 257 * <pre> 258 * Set s = SetUtils.synchronizedSet(mySet); 259 * synchronized (s) { 260 * Iterator i = s.iterator(); 261 * while (i.hasNext()) { 262 * process (i.next()); 263 * } 264 * } 265 * </pre> 266 * 267 * This method is just a wrapper for {@link Collections#synchronizedSortedSet(SortedSet)}. 268 * 269 * @param <E> the element type 270 * @param set the sorted set to synchronize, must not be null 271 * @return a synchronized set backed by the given set 272 * @throws IllegalArgumentException if the set is null 273 */ 274 public static <E> SortedSet<E> synchronizedSortedSet(final SortedSet<E> set) { 275 return Collections.synchronizedSortedSet(set); 276 } 277 278 /** 279 * Returns an unmodifiable sorted set backed by the given sorted set. 280 * <p> 281 * This method uses the implementation in the decorators subpackage. 282 * 283 * @param <E> the element type 284 * @param set the sorted set to make unmodifiable, must not be null 285 * @return an unmodifiable set backed by the given set 286 * @throws IllegalArgumentException if the set is null 287 */ 288 public static <E> SortedSet<E> unmodifiableSortedSet(final SortedSet<E> set) { 289 return UnmodifiableSortedSet.unmodifiableSortedSet(set); 290 } 291 292 /** 293 * Returns a predicated (validating) sorted set backed by the given sorted set. 294 * <p> 295 * Only objects that pass the test in the given predicate can be added to the set. 296 * Trying to add an invalid object results in an IllegalArgumentException. 297 * It is important not to use the original set after invoking this method, 298 * as it is a backdoor for adding invalid objects. 299 * 300 * @param <E> the element type 301 * @param set the sorted set to predicate, must not be null 302 * @param predicate the predicate for the sorted set, must not be null 303 * @return a predicated sorted set backed by the given sorted set 304 * @throws IllegalArgumentException if the Set or Predicate is null 305 */ 306 public static <E> SortedSet<E> predicatedSortedSet(final SortedSet<E> set, final Predicate<? super E> predicate) { 307 return PredicatedSortedSet.predicatedSortedSet(set, predicate); 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 * <p> 317 * Existing entries in the specified set will not be transformed. 318 * If you want that behaviour, see {@link TransformedSortedSet#transformedSortedSet}. 319 * 320 * @param <E> the element type 321 * @param set the set to transform, must not be null 322 * @param transformer the transformer for the set, must not be null 323 * @return a transformed set backed by the given set 324 * @throws IllegalArgumentException if the Set or Transformer is null 325 */ 326 public static <E> SortedSet<E> transformedSortedSet(final SortedSet<E> set, 327 final Transformer<? super E, ? extends E> transformer) { 328 return TransformedSortedSet.transformingSortedSet(set, transformer); 329 } 330 331}