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.AbstractSet; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.HashSet; 024import java.util.IdentityHashMap; 025import java.util.Iterator; 026import java.util.NavigableSet; 027import java.util.Objects; 028import java.util.Set; 029import java.util.SortedSet; 030import java.util.TreeSet; 031 032import org.apache.commons.collections4.set.ListOrderedSet; 033import org.apache.commons.collections4.set.PredicatedNavigableSet; 034import org.apache.commons.collections4.set.PredicatedSet; 035import org.apache.commons.collections4.set.PredicatedSortedSet; 036import org.apache.commons.collections4.set.TransformedNavigableSet; 037import org.apache.commons.collections4.set.TransformedSet; 038import org.apache.commons.collections4.set.TransformedSortedSet; 039import org.apache.commons.collections4.set.UnmodifiableNavigableSet; 040import org.apache.commons.collections4.set.UnmodifiableSet; 041import org.apache.commons.collections4.set.UnmodifiableSortedSet; 042 043/** 044 * Provides utility methods and decorators for 045 * {@link Set} and {@link SortedSet} instances. 046 * 047 * @since 2.1 048 */ 049public class SetUtils { 050 051 /** 052 * An unmodifiable <strong>view</strong> of a set that may be backed by other sets. 053 * <p> 054 * If the decorated sets change, this view will change as well. The contents 055 * of this view can be transferred to another instance via the {@link #copyInto(Set)} 056 * and {@link #toSet()} methods. 057 * </p> 058 * 059 * @param <E> the element type 060 * @since 4.1 061 */ 062 public abstract static class SetView<E> extends AbstractSet<E> { 063 064 /** 065 * Constructs a new instance. 066 */ 067 public SetView() { 068 // empty 069 } 070 071 /** 072 * Copies the contents of this view into the provided set. 073 * 074 * @param <S> the set type 075 * @param set the set for copying the contents 076 */ 077 public <S extends Set<E>> void copyInto(final S set) { 078 CollectionUtils.addAll(set, this); 079 } 080 081 /** 082 * Return an iterator for this view; the returned iterator is 083 * not required to be unmodifiable. 084 * @return a new iterator for this view 085 */ 086 protected abstract Iterator<E> createIterator(); 087 088 @Override 089 public Iterator<E> iterator() { 090 return IteratorUtils.unmodifiableIterator(createIterator()); 091 } 092 093 @Override 094 public int size() { 095 return IteratorUtils.size(iterator()); 096 } 097 098 /** 099 * Returns a new set containing the contents of this view. 100 * 101 * @return a new set containing all elements of this view 102 */ 103 public Set<E> toSet() { 104 final Set<E> set = new HashSet<>(size()); 105 copyInto(set); 106 return set; 107 } 108 } 109 110 /** 111 * An empty unmodifiable sorted set. 112 * This is not provided in the JDK. 113 */ 114 @SuppressWarnings("rawtypes") 115 public static final SortedSet EMPTY_SORTED_SET = 116 UnmodifiableSortedSet.unmodifiableSortedSet(new TreeSet<>()); 117 118 /** 119 * Returns an unmodifiable <strong>view</strong> containing the difference of the given 120 * {@link Set}s, denoted by {@code a \ b} (or {@code a - b}). 121 * <p> 122 * The returned view contains all elements of {@code a} that are not a member 123 * of {@code b}. 124 * </p> 125 * 126 * @param <E> the generic type that is able to represent the types contained 127 * in both input sets. 128 * @param setA the set to subtract from, must not be null 129 * @param setB the set to subtract, must not be null 130 * @return a view of the relative complement of the two sets 131 * @since 4.1 132 */ 133 public static <E> SetView<E> difference(final Set<? extends E> setA, final Set<? extends E> setB) { 134 Objects.requireNonNull(setA, "setA"); 135 Objects.requireNonNull(setB, "setB"); 136 137 final Predicate<E> notContainedInB = object -> !setB.contains(object); 138 139 return new SetView<E>() { 140 @Override 141 public boolean contains(final Object o) { 142 return setA.contains(o) && !setB.contains(o); 143 } 144 145 @Override 146 public Iterator<E> createIterator() { 147 return IteratorUtils.filteredIterator(setA.iterator(), notContainedInB); 148 } 149 }; 150 } 151 152 /** 153 * Returns an unmodifiable <strong>view</strong> of the symmetric difference of the given 154 * {@link Set}s. 155 * <p> 156 * The returned view contains all elements of {@code a} and {@code b} that are 157 * not a member of the other set. 158 * </p> 159 * <p> 160 * This is equivalent to {@code union(difference(a, b), difference(b, a))}. 161 * </p> 162 * 163 * @param <E> the generic type that is able to represent the types contained 164 * in both input sets. 165 * @param setA the first set, must not be null 166 * @param setB the second set, must not be null 167 * @return a view of the symmetric difference of the two sets 168 * @since 4.1 169 */ 170 public static <E> SetView<E> disjunction(final Set<? extends E> setA, final Set<? extends E> setB) { 171 Objects.requireNonNull(setA, "setA"); 172 Objects.requireNonNull(setB, "setB"); 173 174 final SetView<E> aMinusB = difference(setA, setB); 175 final SetView<E> bMinusA = difference(setB, setA); 176 177 return new SetView<E>() { 178 @Override 179 public boolean contains(final Object o) { 180 return setA.contains(o) ^ setB.contains(o); 181 } 182 183 @Override 184 public Iterator<E> createIterator() { 185 return IteratorUtils.chainedIterator(aMinusB.iterator(), bMinusA.iterator()); 186 } 187 188 @Override 189 public boolean isEmpty() { 190 return aMinusB.isEmpty() && bMinusA.isEmpty(); 191 } 192 193 @Override 194 public int size() { 195 return aMinusB.size() + bMinusA.size(); 196 } 197 }; 198 } 199 200 /** 201 * Returns an immutable empty set if the argument is {@code null}, 202 * or the argument itself otherwise. 203 * 204 * @param <T> the element type 205 * @param set the set, possibly {@code null} 206 * @return an empty set if the argument is {@code null} 207 */ 208 public static <T> Set<T> emptyIfNull(final Set<T> set) { 209 return set == null ? Collections.<T>emptySet() : set; 210 } 211 212 /** 213 * Gets a typed empty unmodifiable Set. 214 * 215 * @param <E> the element type 216 * @return an empty Set 217 */ 218 public static <E> Set<E> emptySet() { 219 return Collections.<E>emptySet(); 220 } 221 222 /** 223 * Gets a typed empty unmodifiable sorted set. 224 * 225 * @param <E> the element type 226 * @return an empty sorted Set 227 */ 228 @SuppressWarnings("unchecked") // empty set is OK for any type 229 public static <E> SortedSet<E> emptySortedSet() { 230 return EMPTY_SORTED_SET; 231 } 232 233 /** 234 * Generates a hash code using the algorithm specified in 235 * {@link java.util.Set#hashCode()}. 236 * <p> 237 * This method is useful for implementing {@code Set} when you cannot 238 * extend AbstractSet. The method takes Collection instances to enable other 239 * collection types to use the Set implementation algorithm. 240 * </p> 241 * 242 * @param <T> the element type 243 * @see java.util.Set#hashCode() 244 * @param set the set to calculate the hash code for, may be null 245 * @return the hash code 246 */ 247 public static <T> int hashCodeForSet(final Collection<T> set) { 248 if (set == null) { 249 return 0; 250 } 251 252 int hashCode = 0; 253 for (final T obj : set) { 254 if (obj != null) { 255 hashCode += obj.hashCode(); 256 } 257 } 258 return hashCode; 259 } 260 261 /** 262 * Creates a set from the given items. If the passed var-args argument is {@code 263 * null}, then the method returns {@code null}. 264 * 265 * @param <E> the element type 266 * @param items the elements that make up the new set 267 * @return a set 268 * @since 4.3 269 */ 270 public static <E> HashSet<E> hashSet(final E... items) { 271 if (items == null) { 272 return null; 273 } 274 return new HashSet<>(Arrays.asList(items)); 275 } 276 277 /** 278 * Returns an unmodifiable <strong>view</strong> of the intersection of the given {@link Set}s. 279 * <p> 280 * The returned view contains all elements that are members of both input sets 281 * ({@code a} and {@code b}). 282 * </p> 283 * 284 * @param <E> the generic type that is able to represent the types contained 285 * in both input sets. 286 * @param setA the first set, must not be null 287 * @param setB the second set, must not be null 288 * @return a view of the intersection of the two sets 289 * @since 4.1 290 */ 291 public static <E> SetView<E> intersection(final Set<? extends E> setA, final Set<? extends E> setB) { 292 Objects.requireNonNull(setA, "setA"); 293 Objects.requireNonNull(setB, "setB"); 294 295 return new SetView<E>() { 296 @Override 297 public boolean contains(final Object o) { 298 return setA.contains(o) && setB.contains(o); 299 } 300 301 @Override 302 public Iterator<E> createIterator() { 303 return IteratorUtils.filteredIterator(setA.iterator(), setB::contains); 304 } 305 }; 306 } 307 308 /** 309 * Tests two sets for equality as per the {@code equals()} contract 310 * in {@link java.util.Set#equals(Object)}. 311 * <p> 312 * This method is useful for implementing {@code Set} when you cannot 313 * extend AbstractSet. The method takes Collection instances to enable other 314 * collection types to use the Set implementation algorithm. 315 * </p> 316 * <p> 317 * The relevant text (slightly paraphrased as this is a static method) is: 318 * </p> 319 * <blockquote> 320 * <p>Two sets are considered equal if they have 321 * the same size, and every member of the first set is contained in 322 * the second. This ensures that the {@code equals} method works 323 * properly across different implementations of the {@code Set} 324 * interface. 325 * </p> 326 * <p> 327 * This implementation first checks if the two sets are the same object: 328 * if so it returns {@code true}. Then, it checks if the two sets are 329 * identical in size; if not, it returns false. If so, it returns 330 * {@code a.containsAll((Collection) b)}. 331 * </p> 332 * </blockquote> 333 * 334 * @see java.util.Set 335 * @param set1 the first set, may be null 336 * @param set2 the second set, may be null 337 * @return whether the sets are equal by value comparison 338 */ 339 public static boolean isEqualSet(final Collection<?> set1, final Collection<?> set2) { 340 if (set1 == set2) { 341 return true; 342 } 343 if (set1 == null || set2 == null || set1.size() != set2.size()) { 344 return false; 345 } 346 347 return set1.containsAll(set2); 348 } 349 350 /** 351 * Returns a new hash set that matches elements based on {@code ==} not 352 * {@code equals()}. 353 * <p> 354 * <strong>This set will violate the detail of various Set contracts.</strong> 355 * As a general rule, don't compare this set to other sets. In particular, you can't 356 * use decorators like {@link ListOrderedSet} on it, which silently assume that these 357 * contracts are fulfilled. 358 * </p> 359 * <p> 360 * <strong>Note that the returned set is not synchronized and is not thread-safe.</strong> 361 * If you wish to use this set from multiple threads concurrently, you must use 362 * appropriate synchronization. The simplest approach is to wrap this map 363 * using {@link java.util.Collections#synchronizedSet(Set)}. This class may throw 364 * exceptions when accessed by concurrent threads without synchronization. 365 * </p> 366 * 367 * @param <E> the element type 368 * @return a new identity hash set 369 * @since 4.1 370 */ 371 public static <E> Set<E> newIdentityHashSet() { 372 return Collections.newSetFromMap(new IdentityHashMap<>()); 373 } 374 375 /** 376 * Returns a set that maintains the order of elements that are added 377 * backed by the given set. 378 * <p> 379 * If an element is added twice, the order is determined by the first add. 380 * The order is observed through the iterator or toArray. 381 * </p> 382 * 383 * @param <E> the element type 384 * @param set the set to order, must not be null 385 * @return an ordered set backed by the given set 386 * @throws NullPointerException if the set is null 387 */ 388 public static <E> Set<E> orderedSet(final Set<E> set) { 389 return ListOrderedSet.listOrderedSet(set); 390 } 391 392 /** 393 * Returns a predicated (validating) navigable set backed by the given navigable set. 394 * <p> 395 * Only objects that pass the test in the given predicate can be added to the set. 396 * Trying to add an invalid object results in an IllegalArgumentException. 397 * It is important not to use the original set after invoking this method, 398 * as it is a backdoor for adding invalid objects. 399 * </p> 400 * 401 * @param <E> the element type 402 * @param set the navigable set to predicate, must not be null 403 * @param predicate the predicate for the navigable set, must not be null 404 * @return a predicated navigable set backed by the given navigable set 405 * @throws NullPointerException if the set or predicate is null 406 * @since 4.1 407 */ 408 public static <E> SortedSet<E> predicatedNavigableSet(final NavigableSet<E> set, 409 final Predicate<? super E> predicate) { 410 return PredicatedNavigableSet.predicatedNavigableSet(set, predicate); 411 } 412 413 /** 414 * Returns a predicated (validating) set backed by the given set. 415 * <p> 416 * Only objects that pass the test in the given predicate can be added to the set. 417 * Trying to add an invalid object results in an IllegalArgumentException. 418 * It is important not to use the original set after invoking this method, 419 * as it is a backdoor for adding invalid objects. 420 * </p> 421 * 422 * @param <E> the element type 423 * @param set the set to predicate, must not be null 424 * @param predicate the predicate for the set, must not be null 425 * @return a predicated set backed by the given set 426 * @throws NullPointerException if the set or predicate is null 427 */ 428 public static <E> Set<E> predicatedSet(final Set<E> set, final Predicate<? super E> predicate) { 429 return PredicatedSet.predicatedSet(set, predicate); 430 } 431 432 /** 433 * Returns a predicated (validating) sorted set backed by the given sorted set. 434 * <p> 435 * Only objects that pass the test in the given predicate can be added to the set. 436 * Trying to add an invalid object results in an IllegalArgumentException. 437 * It is important not to use the original set after invoking this method, 438 * as it is a backdoor for adding invalid objects. 439 * </p> 440 * 441 * @param <E> the element type 442 * @param set the sorted set to predicate, must not be null 443 * @param predicate the predicate for the sorted set, must not be null 444 * @return a predicated sorted set backed by the given sorted set 445 * @throws NullPointerException if the set or predicate is null 446 */ 447 public static <E> SortedSet<E> predicatedSortedSet(final SortedSet<E> set, 448 final Predicate<? super E> predicate) { 449 return PredicatedSortedSet.predicatedSortedSet(set, predicate); 450 } 451 452 /** 453 * Returns a synchronized set backed by the given set. 454 * <p> 455 * You must manually synchronize on the returned set's iterator to 456 * avoid non-deterministic behavior: 457 * </p> 458 * 459 * <pre> 460 * Sets s = SetUtils.synchronizedSet(mySet); 461 * synchronized (s) { 462 * Iterator i = s.iterator(); 463 * while (i.hasNext()) { 464 * process (i.next()); 465 * } 466 * } 467 * </pre> 468 * 469 * <p> 470 * This method is just a wrapper for {@link Collections#synchronizedSet(Set)}. 471 * </p> 472 * 473 * @param <E> the element type 474 * @param set the set to synchronize, must not be null 475 * @return a synchronized set backed by the given set 476 * @throws NullPointerException if the set is null 477 */ 478 public static <E> Set<E> synchronizedSet(final Set<E> set) { 479 return Collections.synchronizedSet(set); 480 } 481 482 // SortedSet 483 /** 484 * Returns a synchronized sorted set backed by the given sorted set. 485 * <p> 486 * You must manually synchronize on the returned set's iterator to 487 * avoid non-deterministic behavior: 488 * </p> 489 * 490 * <pre> 491 * Set s = SetUtils.synchronizedSortedSet(mySet); 492 * synchronized (s) { 493 * Iterator i = s.iterator(); 494 * while (i.hasNext()) { 495 * process (i.next()); 496 * } 497 * } 498 * </pre> 499 * 500 * <p> 501 * This method is just a wrapper for {@link Collections#synchronizedSortedSet(SortedSet)}. 502 * </p> 503 * 504 * @param <E> the element type 505 * @param set the sorted set to synchronize, must not be null 506 * @return a synchronized set backed by the given set 507 * @throws NullPointerException if the set is null 508 */ 509 public static <E> SortedSet<E> synchronizedSortedSet(final SortedSet<E> set) { 510 return Collections.synchronizedSortedSet(set); 511 } 512 513 /** 514 * Returns a transformed navigable set backed by the given navigable set. 515 * <p> 516 * Each object is passed through the transformer as it is added to the 517 * Set. It is important not to use the original set after invoking this 518 * method, as it is a backdoor for adding untransformed objects. 519 * </p> 520 * <p> 521 * Existing entries in the specified set will not be transformed. 522 * If you want that behavior, see {@link TransformedNavigableSet#transformedNavigableSet}. 523 * </p> 524 * 525 * @param <E> the element type 526 * @param set the navigable set to transform, must not be null 527 * @param transformer the transformer for the set, must not be null 528 * @return a transformed set backed by the given set 529 * @throws NullPointerException if the set or transformer is null 530 * @since 4.1 531 */ 532 public static <E> SortedSet<E> transformedNavigableSet(final NavigableSet<E> set, 533 final Transformer<? super E, ? extends E> transformer) { 534 return TransformedNavigableSet.transformingNavigableSet(set, transformer); 535 } 536 537 /** 538 * Returns a transformed set backed by the given set. 539 * <p> 540 * Each object is passed through the transformer as it is added to the 541 * Set. It is important not to use the original set after invoking this 542 * method, as it is a backdoor for adding untransformed objects. 543 * </p> 544 * <p> 545 * Existing entries in the specified set will not be transformed. 546 * If you want that behavior, see {@link TransformedSet#transformedSet}. 547 * </p> 548 * 549 * @param <E> the element type 550 * @param set the set to transform, must not be null 551 * @param transformer the transformer for the set, must not be null 552 * @return a transformed set backed by the given set 553 * @throws NullPointerException if the set or transformer is null 554 */ 555 public static <E> Set<E> transformedSet(final Set<E> set, 556 final Transformer<? super E, ? extends E> transformer) { 557 return TransformedSet.transformingSet(set, transformer); 558 } 559 560 /** 561 * Returns a transformed sorted set backed by the given set. 562 * <p> 563 * Each object is passed through the transformer as it is added to the 564 * Set. It is important not to use the original set after invoking this 565 * method, as it is a backdoor for adding untransformed objects. 566 * </p> 567 * <p> 568 * Existing entries in the specified set will not be transformed. 569 * If you want that behavior, see {@link TransformedSortedSet#transformedSortedSet}. 570 * </p> 571 * 572 * @param <E> the element type 573 * @param set the set to transform, must not be null 574 * @param transformer the transformer for the set, must not be null 575 * @return a transformed set backed by the given set 576 * @throws NullPointerException if the set or transformer is null 577 */ 578 public static <E> SortedSet<E> transformedSortedSet(final SortedSet<E> set, 579 final Transformer<? super E, ? extends E> transformer) { 580 return TransformedSortedSet.transformingSortedSet(set, transformer); 581 } 582 583 // Set operations 584 585 /** 586 * Returns an unmodifiable <strong>view</strong> of the union of the given {@link Set}s. 587 * <p> 588 * The returned view contains all elements of {@code a} and {@code b}. 589 * </p> 590 * 591 * @param <E> the generic type that is able to represent the types contained 592 * in both input sets. 593 * @param setA the first set, must not be null 594 * @param setB the second set, must not be null 595 * @return a view of the union of the two set 596 * @throws NullPointerException if either input set is null 597 * @since 4.1 598 */ 599 public static <E> SetView<E> union(final Set<? extends E> setA, final Set<? extends E> setB) { 600 Objects.requireNonNull(setA, "setA"); 601 Objects.requireNonNull(setB, "setB"); 602 603 final SetView<E> bMinusA = difference(setB, setA); 604 605 return new SetView<E>() { 606 @Override 607 public boolean contains(final Object o) { 608 return setA.contains(o) || setB.contains(o); 609 } 610 611 @Override 612 public Iterator<E> createIterator() { 613 return IteratorUtils.chainedIterator(setA.iterator(), bMinusA.iterator()); 614 } 615 616 @Override 617 public boolean isEmpty() { 618 return setA.isEmpty() && setB.isEmpty(); 619 } 620 621 @Override 622 public int size() { 623 return setA.size() + bMinusA.size(); 624 } 625 }; 626 } 627 628 /** 629 * Returns an unmodifiable navigable set backed by the given navigable set. 630 * <p> 631 * This method uses the implementation in the decorators subpackage. 632 * </p> 633 * 634 * @param <E> the element type 635 * @param set the navigable set to make unmodifiable, must not be null 636 * @return an unmodifiable set backed by the given set 637 * @throws NullPointerException if the set is null 638 * @since 4.1 639 */ 640 public static <E> SortedSet<E> unmodifiableNavigableSet(final NavigableSet<E> set) { 641 return UnmodifiableNavigableSet.unmodifiableNavigableSet(set); 642 } 643 644 /** 645 * Creates an unmodifiable set from the given items. If the passed var-args argument is {@code 646 * null}, then the method returns {@code null}. 647 * @param <E> the element type 648 * @param items the elements that make up the new set 649 * @return a set 650 * @since 4.3 651 */ 652 public static <E> Set<E> unmodifiableSet(final E... items) { 653 if (items == null) { 654 return null; 655 } 656 return UnmodifiableSet.unmodifiableSet(hashSet(items)); 657 } 658 659 /** 660 * Returns an unmodifiable set backed by the given set. 661 * <p> 662 * This method uses the implementation in the decorators subpackage. 663 * </p> 664 * 665 * @param <E> the element type 666 * @param set the set to make unmodifiable, must not be null 667 * @return an unmodifiable set backed by the given set 668 * @throws NullPointerException if the set is null 669 */ 670 public static <E> Set<E> unmodifiableSet(final Set<? extends E> set) { 671 return UnmodifiableSet.unmodifiableSet(set); 672 } 673 674 /** 675 * Returns an unmodifiable sorted set backed by the given sorted set. 676 * <p> 677 * This method uses the implementation in the decorators subpackage. 678 * </p> 679 * 680 * @param <E> the element type 681 * @param set the sorted set to make unmodifiable, must not be null 682 * @return an unmodifiable set backed by the given set 683 * @throws NullPointerException if the set is null 684 */ 685 public static <E> SortedSet<E> unmodifiableSortedSet(final SortedSet<E> set) { 686 return UnmodifiableSortedSet.unmodifiableSortedSet(set); 687 } 688 689 /** 690 * Don't allow instances. 691 */ 692 private SetUtils() { 693 // empty 694 } 695 696}