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.lang.reflect.Array; 020 import java.util.ArrayList; 021 import java.util.Collection; 022 import java.util.Enumeration; 023 import java.util.HashMap; 024 import java.util.HashSet; 025 import java.util.Iterator; 026 import java.util.List; 027 import java.util.ListIterator; 028 import java.util.Map; 029 import java.util.Set; 030 031 import org.apache.commons.collections.collection.PredicatedCollection; 032 import org.apache.commons.collections.collection.SynchronizedCollection; 033 import org.apache.commons.collections.collection.TransformedCollection; 034 import org.apache.commons.collections.collection.TypedCollection; 035 import org.apache.commons.collections.collection.UnmodifiableBoundedCollection; 036 import org.apache.commons.collections.collection.UnmodifiableCollection; 037 038 /** 039 * Provides utility methods and decorators for {@link Collection} instances. 040 * 041 * @since Commons Collections 1.0 042 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $ 043 * 044 * @author Rodney Waldhoff 045 * @author Paul Jack 046 * @author Stephen Colebourne 047 * @author Steve Downey 048 * @author Herve Quiroz 049 * @author Peter KoBek 050 * @author Matthew Hawthorne 051 * @author Janek Bogucki 052 * @author Phil Steitz 053 * @author Steven Melzer 054 * @author Jon Schewe 055 * @author Neil O'Toole 056 * @author Stephen Smith 057 */ 058 public class CollectionUtils { 059 060 /** Constant to avoid repeated object creation */ 061 private static Integer INTEGER_ONE = new Integer(1); 062 063 /** 064 * An empty unmodifiable collection. 065 * The JDK provides empty Set and List implementations which could be used for 066 * this purpose. However they could be cast to Set or List which might be 067 * undesirable. This implementation only implements Collection. 068 */ 069 public static final Collection EMPTY_COLLECTION = UnmodifiableCollection.decorate(new ArrayList()); 070 071 /** 072 * <code>CollectionUtils</code> should not normally be instantiated. 073 */ 074 public CollectionUtils() { 075 } 076 077 /** 078 * Returns a {@link Collection} containing the union 079 * of the given {@link Collection}s. 080 * <p> 081 * The cardinality of each element in the returned {@link Collection} 082 * will be equal to the maximum of the cardinality of that element 083 * in the two given {@link Collection}s. 084 * 085 * @param a the first collection, must not be null 086 * @param b the second collection, must not be null 087 * @return the union of the two collections 088 * @see Collection#addAll 089 */ 090 public static Collection union(final Collection a, final Collection b) { 091 ArrayList list = new ArrayList(); 092 Map mapa = getCardinalityMap(a); 093 Map mapb = getCardinalityMap(b); 094 Set elts = new HashSet(a); 095 elts.addAll(b); 096 Iterator it = elts.iterator(); 097 while(it.hasNext()) { 098 Object obj = it.next(); 099 for(int i=0,m=Math.max(getFreq(obj,mapa),getFreq(obj,mapb));i<m;i++) { 100 list.add(obj); 101 } 102 } 103 return list; 104 } 105 106 /** 107 * Returns a {@link Collection} containing the intersection 108 * of the given {@link Collection}s. 109 * <p> 110 * The cardinality of each element in the returned {@link Collection} 111 * will be equal to the minimum of the cardinality of that element 112 * in the two given {@link Collection}s. 113 * 114 * @param a the first collection, must not be null 115 * @param b the second collection, must not be null 116 * @return the intersection of the two collections 117 * @see Collection#retainAll 118 * @see #containsAny 119 */ 120 public static Collection intersection(final Collection a, final Collection b) { 121 ArrayList list = new ArrayList(); 122 Map mapa = getCardinalityMap(a); 123 Map mapb = getCardinalityMap(b); 124 Set elts = new HashSet(a); 125 elts.addAll(b); 126 Iterator it = elts.iterator(); 127 while(it.hasNext()) { 128 Object obj = it.next(); 129 for(int i=0,m=Math.min(getFreq(obj,mapa),getFreq(obj,mapb));i<m;i++) { 130 list.add(obj); 131 } 132 } 133 return list; 134 } 135 136 /** 137 * Returns a {@link Collection} containing the exclusive disjunction 138 * (symmetric difference) of the given {@link Collection}s. 139 * <p> 140 * The cardinality of each element <i>e</i> in the returned {@link Collection} 141 * will be equal to 142 * <tt>max(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>)) - min(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>))</tt>. 143 * <p> 144 * This is equivalent to 145 * <tt>{@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})</tt> 146 * or 147 * <tt>{@link #union union}({@link #subtract subtract(a,b)},{@link #subtract subtract(b,a)})</tt>. 148 * 149 * @param a the first collection, must not be null 150 * @param b the second collection, must not be null 151 * @return the symmetric difference of the two collections 152 */ 153 public static Collection disjunction(final Collection a, final Collection b) { 154 ArrayList list = new ArrayList(); 155 Map mapa = getCardinalityMap(a); 156 Map mapb = getCardinalityMap(b); 157 Set elts = new HashSet(a); 158 elts.addAll(b); 159 Iterator it = elts.iterator(); 160 while(it.hasNext()) { 161 Object obj = it.next(); 162 for(int i=0,m=((Math.max(getFreq(obj,mapa),getFreq(obj,mapb)))-(Math.min(getFreq(obj,mapa),getFreq(obj,mapb))));i<m;i++) { 163 list.add(obj); 164 } 165 } 166 return list; 167 } 168 169 /** 170 * Returns a new {@link Collection} containing <tt><i>a</i> - <i>b</i></tt>. 171 * The cardinality of each element <i>e</i> in the returned {@link Collection} 172 * will be the cardinality of <i>e</i> in <i>a</i> minus the cardinality 173 * of <i>e</i> in <i>b</i>, or zero, whichever is greater. 174 * 175 * @param a the collection to subtract from, must not be null 176 * @param b the collection to subtract, must not be null 177 * @return a new collection with the results 178 * @see Collection#removeAll 179 */ 180 public static Collection subtract(final Collection a, final Collection b) { 181 ArrayList list = new ArrayList( a ); 182 for (Iterator it = b.iterator(); it.hasNext();) { 183 list.remove(it.next()); 184 } 185 return list; 186 } 187 188 /** 189 * Returns <code>true</code> iff at least one element is in both collections. 190 * <p> 191 * In other words, this method returns <code>true</code> iff the 192 * {@link #intersection} of <i>coll1</i> and <i>coll2</i> is not empty. 193 * 194 * @param coll1 the first collection, must not be null 195 * @param coll2 the first collection, must not be null 196 * @return <code>true</code> iff the intersection of the collections is non-empty 197 * @since 2.1 198 * @see #intersection 199 */ 200 public static boolean containsAny(final Collection coll1, final Collection coll2) { 201 if (coll1.size() < coll2.size()) { 202 for (Iterator it = coll1.iterator(); it.hasNext();) { 203 if (coll2.contains(it.next())) { 204 return true; 205 } 206 } 207 } else { 208 for (Iterator it = coll2.iterator(); it.hasNext();) { 209 if (coll1.contains(it.next())) { 210 return true; 211 } 212 } 213 } 214 return false; 215 } 216 217 /** 218 * Returns a {@link Map} mapping each unique element in the given 219 * {@link Collection} to an {@link Integer} representing the number 220 * of occurrences of that element in the {@link Collection}. 221 * <p> 222 * Only those elements present in the collection will appear as 223 * keys in the map. 224 * 225 * @param coll the collection to get the cardinality map for, must not be null 226 * @return the populated cardinality map 227 */ 228 public static Map getCardinalityMap(final Collection coll) { 229 Map count = new HashMap(); 230 for (Iterator it = coll.iterator(); it.hasNext();) { 231 Object obj = it.next(); 232 Integer c = (Integer) (count.get(obj)); 233 if (c == null) { 234 count.put(obj,INTEGER_ONE); 235 } else { 236 count.put(obj,new Integer(c.intValue() + 1)); 237 } 238 } 239 return count; 240 } 241 242 /** 243 * Returns <tt>true</tt> iff <i>a</i> is a sub-collection of <i>b</i>, 244 * that is, iff the cardinality of <i>e</i> in <i>a</i> is less 245 * than or equal to the cardinality of <i>e</i> in <i>b</i>, 246 * for each element <i>e</i> in <i>a</i>. 247 * 248 * @param a the first (sub?) collection, must not be null 249 * @param b the second (super?) collection, must not be null 250 * @return <code>true</code> iff <i>a</i> is a sub-collection of <i>b</i> 251 * @see #isProperSubCollection 252 * @see Collection#containsAll 253 */ 254 public static boolean isSubCollection(final Collection a, final Collection b) { 255 Map mapa = getCardinalityMap(a); 256 Map mapb = getCardinalityMap(b); 257 Iterator it = a.iterator(); 258 while (it.hasNext()) { 259 Object obj = it.next(); 260 if (getFreq(obj, mapa) > getFreq(obj, mapb)) { 261 return false; 262 } 263 } 264 return true; 265 } 266 267 /** 268 * Returns <tt>true</tt> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i>, 269 * that is, iff the cardinality of <i>e</i> in <i>a</i> is less 270 * than or equal to the cardinality of <i>e</i> in <i>b</i>, 271 * for each element <i>e</i> in <i>a</i>, and there is at least one 272 * element <i>f</i> such that the cardinality of <i>f</i> in <i>b</i> 273 * is strictly greater than the cardinality of <i>f</i> in <i>a</i>. 274 * <p> 275 * The implementation assumes 276 * <ul> 277 * <li><code>a.size()</code> and <code>b.size()</code> represent the 278 * total cardinality of <i>a</i> and <i>b</i>, resp. </li> 279 * <li><code>a.size() < Integer.MAXVALUE</code></li> 280 * </ul> 281 * 282 * @param a the first (sub?) collection, must not be null 283 * @param b the second (super?) collection, must not be null 284 * @return <code>true</code> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i> 285 * @see #isSubCollection 286 * @see Collection#containsAll 287 */ 288 public static boolean isProperSubCollection(final Collection a, final Collection b) { 289 return (a.size() < b.size()) && CollectionUtils.isSubCollection(a,b); 290 } 291 292 /** 293 * Returns <tt>true</tt> iff the given {@link Collection}s contain 294 * exactly the same elements with exactly the same cardinalities. 295 * <p> 296 * That is, iff the cardinality of <i>e</i> in <i>a</i> is 297 * equal to the cardinality of <i>e</i> in <i>b</i>, 298 * for each element <i>e</i> in <i>a</i> or <i>b</i>. 299 * 300 * @param a the first collection, must not be null 301 * @param b the second collection, must not be null 302 * @return <code>true</code> iff the collections contain the same elements with the same cardinalities. 303 */ 304 public static boolean isEqualCollection(final Collection a, final Collection b) { 305 if(a.size() != b.size()) { 306 return false; 307 } else { 308 Map mapa = getCardinalityMap(a); 309 Map mapb = getCardinalityMap(b); 310 if(mapa.size() != mapb.size()) { 311 return false; 312 } else { 313 Iterator it = mapa.keySet().iterator(); 314 while(it.hasNext()) { 315 Object obj = it.next(); 316 if(getFreq(obj,mapa) != getFreq(obj,mapb)) { 317 return false; 318 } 319 } 320 return true; 321 } 322 } 323 } 324 325 /** 326 * Returns the number of occurrences of <i>obj</i> in <i>coll</i>. 327 * 328 * @param obj the object to find the cardinality of 329 * @param coll the collection to search 330 * @return the the number of occurrences of obj in coll 331 */ 332 public static int cardinality(Object obj, final Collection coll) { 333 if (coll instanceof Set) { 334 return (coll.contains(obj) ? 1 : 0); 335 } 336 if (coll instanceof Bag) { 337 return ((Bag) coll).getCount(obj); 338 } 339 int count = 0; 340 if (obj == null) { 341 for (Iterator it = coll.iterator();it.hasNext();) { 342 if (it.next() == null) { 343 count++; 344 } 345 } 346 } else { 347 for (Iterator it = coll.iterator();it.hasNext();) { 348 if (obj.equals(it.next())) { 349 count++; 350 } 351 } 352 } 353 return count; 354 } 355 356 /** 357 * Finds the first element in the given collection which matches the given predicate. 358 * <p> 359 * If the input collection or predicate is null, or no element of the collection 360 * matches the predicate, null is returned. 361 * 362 * @param collection the collection to search, may be null 363 * @param predicate the predicate to use, may be null 364 * @return the first element of the collection which matches the predicate or null if none could be found 365 */ 366 public static Object find(Collection collection, Predicate predicate) { 367 if (collection != null && predicate != null) { 368 for (Iterator iter = collection.iterator(); iter.hasNext();) { 369 Object item = iter.next(); 370 if (predicate.evaluate(item)) { 371 return item; 372 } 373 } 374 } 375 return null; 376 } 377 378 /** 379 * Executes the given closure on each element in the collection. 380 * <p> 381 * If the input collection or closure is null, there is no change made. 382 * 383 * @param collection the collection to get the input from, may be null 384 * @param closure the closure to perform, may be null 385 */ 386 public static void forAllDo(Collection collection, Closure closure) { 387 if (collection != null && closure != null) { 388 for (Iterator it = collection.iterator(); it.hasNext();) { 389 closure.execute(it.next()); 390 } 391 } 392 } 393 394 /** 395 * Filter the collection by applying a Predicate to each element. If the 396 * predicate returns false, remove the element. 397 * <p> 398 * If the input collection or predicate is null, there is no change made. 399 * 400 * @param collection the collection to get the input from, may be null 401 * @param predicate the predicate to use as a filter, may be null 402 */ 403 public static void filter(Collection collection, Predicate predicate) { 404 if (collection != null && predicate != null) { 405 for (Iterator it = collection.iterator(); it.hasNext();) { 406 if (predicate.evaluate(it.next()) == false) { 407 it.remove(); 408 } 409 } 410 } 411 } 412 413 /** 414 * Transform the collection by applying a Transformer to each element. 415 * <p> 416 * If the input collection or transformer is null, there is no change made. 417 * <p> 418 * This routine is best for Lists, for which set() is used to do the 419 * transformations "in place." For other Collections, clear() and addAll() 420 * are used to replace elements. 421 * <p> 422 * If the input collection controls its input, such as a Set, and the 423 * Transformer creates duplicates (or are otherwise invalid), the 424 * collection may reduce in size due to calling this method. 425 * 426 * @param collection the collection to get the input from, may be null 427 * @param transformer the transformer to perform, may be null 428 */ 429 public static void transform(Collection collection, Transformer transformer) { 430 if (collection != null && transformer != null) { 431 if (collection instanceof List) { 432 List list = (List) collection; 433 for (ListIterator it = list.listIterator(); it.hasNext();) { 434 it.set(transformer.transform(it.next())); 435 } 436 } else { 437 Collection resultCollection = collect(collection, transformer); 438 collection.clear(); 439 collection.addAll(resultCollection); 440 } 441 } 442 } 443 444 /** 445 * Counts the number of elements in the input collection that match the predicate. 446 * <p> 447 * A <code>null</code> collection or predicate matches no elements. 448 * 449 * @param inputCollection the collection to get the input from, may be null 450 * @param predicate the predicate to use, may be null 451 * @return the number of matches for the predicate in the collection 452 */ 453 public static int countMatches(Collection inputCollection, Predicate predicate) { 454 int count = 0; 455 if (inputCollection != null && predicate != null) { 456 for (Iterator it = inputCollection.iterator(); it.hasNext();) { 457 if (predicate.evaluate(it.next())) { 458 count++; 459 } 460 } 461 } 462 return count; 463 } 464 465 /** 466 * Answers true if a predicate is true for at least one element of a collection. 467 * <p> 468 * A <code>null</code> collection or predicate returns false. 469 * 470 * @param collection the collection to get the input from, may be null 471 * @param predicate the predicate to use, may be null 472 * @return true if at least one element of the collection matches the predicate 473 */ 474 public static boolean exists(Collection collection, Predicate predicate) { 475 if (collection != null && predicate != null) { 476 for (Iterator it = collection.iterator(); it.hasNext();) { 477 if (predicate.evaluate(it.next())) { 478 return true; 479 } 480 } 481 } 482 return false; 483 } 484 485 /** 486 * Selects all elements from input collection which match the given predicate 487 * into an output collection. 488 * <p> 489 * A <code>null</code> predicate matches no elements. 490 * 491 * @param inputCollection the collection to get the input from, may not be null 492 * @param predicate the predicate to use, may be null 493 * @return the elements matching the predicate (new list) 494 * @throws NullPointerException if the input collection is null 495 */ 496 public static Collection select(Collection inputCollection, Predicate predicate) { 497 ArrayList answer = new ArrayList(inputCollection.size()); 498 select(inputCollection, predicate, answer); 499 return answer; 500 } 501 502 /** 503 * Selects all elements from input collection which match the given predicate 504 * and adds them to outputCollection. 505 * <p> 506 * If the input collection or predicate is null, there is no change to the 507 * output collection. 508 * 509 * @param inputCollection the collection to get the input from, may be null 510 * @param predicate the predicate to use, may be null 511 * @param outputCollection the collection to output into, may not be null 512 */ 513 public static void select(Collection inputCollection, Predicate predicate, Collection outputCollection) { 514 if (inputCollection != null && predicate != null) { 515 for (Iterator iter = inputCollection.iterator(); iter.hasNext();) { 516 Object item = iter.next(); 517 if (predicate.evaluate(item)) { 518 outputCollection.add(item); 519 } 520 } 521 } 522 } 523 524 /** 525 * Selects all elements from inputCollection which don't match the given predicate 526 * into an output collection. 527 * <p> 528 * If the input predicate is <code>null</code>, the result is an empty list. 529 * 530 * @param inputCollection the collection to get the input from, may not be null 531 * @param predicate the predicate to use, may be null 532 * @return the elements <b>not</b> matching the predicate (new list) 533 * @throws NullPointerException if the input collection is null 534 */ 535 public static Collection selectRejected(Collection inputCollection, Predicate predicate) { 536 ArrayList answer = new ArrayList(inputCollection.size()); 537 selectRejected(inputCollection, predicate, answer); 538 return answer; 539 } 540 541 /** 542 * Selects all elements from inputCollection which don't match the given predicate 543 * and adds them to outputCollection. 544 * <p> 545 * If the input predicate is <code>null</code>, no elements are added to <code>outputCollection</code>. 546 * 547 * @param inputCollection the collection to get the input from, may be null 548 * @param predicate the predicate to use, may be null 549 * @param outputCollection the collection to output into, may not be null 550 */ 551 public static void selectRejected(Collection inputCollection, Predicate predicate, Collection outputCollection) { 552 if (inputCollection != null && predicate != null) { 553 for (Iterator iter = inputCollection.iterator(); iter.hasNext();) { 554 Object item = iter.next(); 555 if (predicate.evaluate(item) == false) { 556 outputCollection.add(item); 557 } 558 } 559 } 560 } 561 562 /** 563 * Returns a new Collection consisting of the elements of inputCollection transformed 564 * by the given transformer. 565 * <p> 566 * If the input transformer is null, the result is an empty list. 567 * 568 * @param inputCollection the collection to get the input from, may not be null 569 * @param transformer the transformer to use, may be null 570 * @return the transformed result (new list) 571 * @throws NullPointerException if the input collection is null 572 */ 573 public static Collection collect(Collection inputCollection, Transformer transformer) { 574 ArrayList answer = new ArrayList(inputCollection.size()); 575 collect(inputCollection, transformer, answer); 576 return answer; 577 } 578 579 /** 580 * Transforms all elements from the inputIterator with the given transformer 581 * and adds them to the outputCollection. 582 * <p> 583 * If the input iterator or transformer is null, the result is an empty list. 584 * 585 * @param inputIterator the iterator to get the input from, may be null 586 * @param transformer the transformer to use, may be null 587 * @return the transformed result (new list) 588 */ 589 public static Collection collect(Iterator inputIterator, Transformer transformer) { 590 ArrayList answer = new ArrayList(); 591 collect(inputIterator, transformer, answer); 592 return answer; 593 } 594 595 /** 596 * Transforms all elements from inputCollection with the given transformer 597 * and adds them to the outputCollection. 598 * <p> 599 * If the input collection or transformer is null, there is no change to the 600 * output collection. 601 * 602 * @param inputCollection the collection to get the input from, may be null 603 * @param transformer the transformer to use, may be null 604 * @param outputCollection the collection to output into, may not be null 605 * @return the outputCollection with the transformed input added 606 * @throws NullPointerException if the output collection is null 607 */ 608 public static Collection collect(Collection inputCollection, final Transformer transformer, final Collection outputCollection) { 609 if (inputCollection != null) { 610 return collect(inputCollection.iterator(), transformer, outputCollection); 611 } 612 return outputCollection; 613 } 614 615 /** 616 * Transforms all elements from the inputIterator with the given transformer 617 * and adds them to the outputCollection. 618 * <p> 619 * If the input iterator or transformer is null, there is no change to the 620 * output collection. 621 * 622 * @param inputIterator the iterator to get the input from, may be null 623 * @param transformer the transformer to use, may be null 624 * @param outputCollection the collection to output into, may not be null 625 * @return the outputCollection with the transformed input added 626 * @throws NullPointerException if the output collection is null 627 */ 628 public static Collection collect(Iterator inputIterator, final Transformer transformer, final Collection outputCollection) { 629 if (inputIterator != null && transformer != null) { 630 while (inputIterator.hasNext()) { 631 Object item = inputIterator.next(); 632 Object value = transformer.transform(item); 633 outputCollection.add(value); 634 } 635 } 636 return outputCollection; 637 } 638 639 //----------------------------------------------------------------------- 640 /** 641 * Adds an element to the collection unless the element is null. 642 * 643 * @param collection the collection to add to, must not be null 644 * @param object the object to add, if null it will not be added 645 * @return true if the collection changed 646 * @throws NullPointerException if the collection is null 647 * @since Commons Collections 3.2 648 */ 649 public static boolean addIgnoreNull(Collection collection, Object object) { 650 return (object == null ? false : collection.add(object)); 651 } 652 653 /** 654 * Adds all elements in the iteration to the given collection. 655 * 656 * @param collection the collection to add to, must not be null 657 * @param iterator the iterator of elements to add, must not be null 658 * @throws NullPointerException if the collection or iterator is null 659 */ 660 public static void addAll(Collection collection, Iterator iterator) { 661 while (iterator.hasNext()) { 662 collection.add(iterator.next()); 663 } 664 } 665 666 /** 667 * Adds all elements in the enumeration to the given collection. 668 * 669 * @param collection the collection to add to, must not be null 670 * @param enumeration the enumeration of elements to add, must not be null 671 * @throws NullPointerException if the collection or enumeration is null 672 */ 673 public static void addAll(Collection collection, Enumeration enumeration) { 674 while (enumeration.hasMoreElements()) { 675 collection.add(enumeration.nextElement()); 676 } 677 } 678 679 /** 680 * Adds all elements in the array to the given collection. 681 * 682 * @param collection the collection to add to, must not be null 683 * @param elements the array of elements to add, must not be null 684 * @throws NullPointerException if the collection or array is null 685 */ 686 public static void addAll(Collection collection, Object[] elements) { 687 for (int i = 0, size = elements.length; i < size; i++) { 688 collection.add(elements[i]); 689 } 690 } 691 692 /** 693 * Given an Object, and an index, returns the nth value in the 694 * object. 695 * <ul> 696 * <li>If obj is a Map, returns the nth value from the <b>keySet</b> iterator, unless 697 * the Map contains an Integer key with integer value = idx, in which case the 698 * corresponding map entry value is returned. If idx exceeds the number of entries in 699 * the map, an empty Iterator is returned. 700 * <li>If obj is a List or an array, returns the nth value, throwing IndexOutOfBoundsException, 701 * ArrayIndexOutOfBoundsException, resp. if the nth value does not exist. 702 * <li>If obj is an iterator, enumeration or Collection, returns the nth value from the iterator, 703 * returning an empty Iterator (resp. Enumeration) if the nth value does not exist. 704 * <li>Returns the original obj if it is null or not a Collection or Iterator. 705 * </ul> 706 * 707 * @param obj the object to get an index of, may be null 708 * @param idx the index to get 709 * @throws IndexOutOfBoundsException 710 * @throws ArrayIndexOutOfBoundsException 711 * 712 * @deprecated use {@link #get(Object, int)} instead. Will be removed in v4.0 713 */ 714 public static Object index(Object obj, int idx) { 715 return index(obj, new Integer(idx)); 716 } 717 718 /** 719 * Given an Object, and a key (index), returns the value associated with 720 * that key in the Object. The following checks are made: 721 * <ul> 722 * <li>If obj is a Map, use the index as a key to get a value. If no match continue. 723 * <li>Check key is an Integer. If not, return the object passed in. 724 * <li>If obj is a Map, get the nth value from the <b>keySet</b> iterator. 725 * If the Map has fewer than n entries, return an empty Iterator. 726 * <li>If obj is a List or an array, get the nth value, throwing IndexOutOfBoundsException, 727 * ArrayIndexOutOfBoundsException, resp. if the nth value does not exist. 728 * <li>If obj is an iterator, enumeration or Collection, get the nth value from the iterator, 729 * returning an empty Iterator (resp. Enumeration) if the nth value does not exist. 730 * <li>Return the original obj. 731 * </ul> 732 * 733 * @param obj the object to get an index of 734 * @param index the index to get 735 * @return the object at the specified index 736 * @throws IndexOutOfBoundsException 737 * @throws ArrayIndexOutOfBoundsException 738 * 739 * @deprecated use {@link #get(Object, int)} instead. Will be removed in v4.0 740 */ 741 public static Object index(Object obj, Object index) { 742 if(obj instanceof Map) { 743 Map map = (Map)obj; 744 if(map.containsKey(index)) { 745 return map.get(index); 746 } 747 } 748 int idx = -1; 749 if(index instanceof Integer) { 750 idx = ((Integer)index).intValue(); 751 } 752 if(idx < 0) { 753 return obj; 754 } 755 else if(obj instanceof Map) { 756 Map map = (Map)obj; 757 Iterator iterator = map.keySet().iterator(); 758 return index(iterator, idx); 759 } 760 else if(obj instanceof List) { 761 return ((List)obj).get(idx); 762 } 763 else if(obj instanceof Object[]) { 764 return ((Object[])obj)[idx]; 765 } 766 else if(obj instanceof Enumeration) { 767 Enumeration it = (Enumeration)obj; 768 while(it.hasMoreElements()) { 769 idx--; 770 if(idx == -1) { 771 return it.nextElement(); 772 } else { 773 it.nextElement(); 774 } 775 } 776 } 777 else if(obj instanceof Iterator) { 778 return index((Iterator)obj, idx); 779 } 780 else if(obj instanceof Collection) { 781 Iterator iterator = ((Collection)obj).iterator(); 782 return index(iterator, idx); 783 } 784 return obj; 785 } 786 787 private static Object index(Iterator iterator, int idx) { 788 while(iterator.hasNext()) { 789 idx--; 790 if(idx == -1) { 791 return iterator.next(); 792 } else { 793 iterator.next(); 794 } 795 } 796 return iterator; 797 } 798 799 /** 800 * Returns the <code>index</code>-th value in <code>object</code>, throwing 801 * <code>IndexOutOfBoundsException</code> if there is no such element or 802 * <code>IllegalArgumentException</code> if <code>object</code> is not an 803 * instance of one of the supported types. 804 * <p> 805 * The supported types, and associated semantics are: 806 * <ul> 807 * <li> Map -- the value returned is the <code>Map.Entry</code> in position 808 * <code>index</code> in the map's <code>entrySet</code> iterator, 809 * if there is such an entry.</li> 810 * <li> List -- this method is equivalent to the list's get method.</li> 811 * <li> Array -- the <code>index</code>-th array entry is returned, 812 * if there is such an entry; otherwise an <code>IndexOutOfBoundsException</code> 813 * is thrown.</li> 814 * <li> Collection -- the value returned is the <code>index</code>-th object 815 * returned by the collection's default iterator, if there is such an element.</li> 816 * <li> Iterator or Enumeration -- the value returned is the 817 * <code>index</code>-th object in the Iterator/Enumeration, if there 818 * is such an element. The Iterator/Enumeration is advanced to 819 * <code>index</code> (or to the end, if <code>index</code> exceeds the 820 * number of entries) as a side effect of this method.</li> 821 * </ul> 822 * 823 * @param object the object to get a value from 824 * @param index the index to get 825 * @return the object at the specified index 826 * @throws IndexOutOfBoundsException if the index is invalid 827 * @throws IllegalArgumentException if the object type is invalid 828 */ 829 public static Object get(Object object, int index) { 830 if (index < 0) { 831 throw new IndexOutOfBoundsException("Index cannot be negative: " + index); 832 } 833 if (object instanceof Map) { 834 Map map = (Map) object; 835 Iterator iterator = map.entrySet().iterator(); 836 return get(iterator, index); 837 } else if (object instanceof List) { 838 return ((List) object).get(index); 839 } else if (object instanceof Object[]) { 840 return ((Object[]) object)[index]; 841 } else if (object instanceof Iterator) { 842 Iterator it = (Iterator) object; 843 while (it.hasNext()) { 844 index--; 845 if (index == -1) { 846 return it.next(); 847 } else { 848 it.next(); 849 } 850 } 851 throw new IndexOutOfBoundsException("Entry does not exist: " + index); 852 } else if (object instanceof Collection) { 853 Iterator iterator = ((Collection) object).iterator(); 854 return get(iterator, index); 855 } else if (object instanceof Enumeration) { 856 Enumeration it = (Enumeration) object; 857 while (it.hasMoreElements()) { 858 index--; 859 if (index == -1) { 860 return it.nextElement(); 861 } else { 862 it.nextElement(); 863 } 864 } 865 throw new IndexOutOfBoundsException("Entry does not exist: " + index); 866 } else if (object == null) { 867 throw new IllegalArgumentException("Unsupported object type: null"); 868 } else { 869 try { 870 return Array.get(object, index); 871 } catch (IllegalArgumentException ex) { 872 throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); 873 } 874 } 875 } 876 877 /** 878 * Gets the size of the collection/iterator specified. 879 * <p> 880 * This method can handles objects as follows 881 * <ul> 882 * <li>Collection - the collection size 883 * <li>Map - the map size 884 * <li>Array - the array size 885 * <li>Iterator - the number of elements remaining in the iterator 886 * <li>Enumeration - the number of elements remaining in the enumeration 887 * </ul> 888 * 889 * @param object the object to get the size of 890 * @return the size of the specified collection 891 * @throws IllegalArgumentException thrown if object is not recognised or null 892 * @since Commons Collections 3.1 893 */ 894 public static int size(Object object) { 895 int total = 0; 896 if (object instanceof Map) { 897 total = ((Map) object).size(); 898 } else if (object instanceof Collection) { 899 total = ((Collection) object).size(); 900 } else if (object instanceof Object[]) { 901 total = ((Object[]) object).length; 902 } else if (object instanceof Iterator) { 903 Iterator it = (Iterator) object; 904 while (it.hasNext()) { 905 total++; 906 it.next(); 907 } 908 } else if (object instanceof Enumeration) { 909 Enumeration it = (Enumeration) object; 910 while (it.hasMoreElements()) { 911 total++; 912 it.nextElement(); 913 } 914 } else if (object == null) { 915 throw new IllegalArgumentException("Unsupported object type: null"); 916 } else { 917 try { 918 total = Array.getLength(object); 919 } catch (IllegalArgumentException ex) { 920 throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); 921 } 922 } 923 return total; 924 } 925 926 /** 927 * Checks if the specified collection/array/iterator is empty. 928 * <p> 929 * This method can handles objects as follows 930 * <ul> 931 * <li>Collection - via collection isEmpty 932 * <li>Map - via map isEmpty 933 * <li>Array - using array size 934 * <li>Iterator - via hasNext 935 * <li>Enumeration - via hasMoreElements 936 * </ul> 937 * <p> 938 * Note: This method is named to avoid clashing with 939 * {@link #isEmpty(Collection)}. 940 * 941 * @param object the object to get the size of, not null 942 * @return true if empty 943 * @throws IllegalArgumentException thrown if object is not recognised or null 944 * @since Commons Collections 3.2 945 */ 946 public static boolean sizeIsEmpty(Object object) { 947 if (object instanceof Collection) { 948 return ((Collection) object).isEmpty(); 949 } else if (object instanceof Map) { 950 return ((Map) object).isEmpty(); 951 } else if (object instanceof Object[]) { 952 return ((Object[]) object).length == 0; 953 } else if (object instanceof Iterator) { 954 return ((Iterator) object).hasNext() == false; 955 } else if (object instanceof Enumeration) { 956 return ((Enumeration) object).hasMoreElements() == false; 957 } else if (object == null) { 958 throw new IllegalArgumentException("Unsupported object type: null"); 959 } else { 960 try { 961 return Array.getLength(object) == 0; 962 } catch (IllegalArgumentException ex) { 963 throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); 964 } 965 } 966 } 967 968 //----------------------------------------------------------------------- 969 /** 970 * Null-safe check if the specified collection is empty. 971 * <p> 972 * Null returns true. 973 * 974 * @param coll the collection to check, may be null 975 * @return true if empty or null 976 * @since Commons Collections 3.2 977 */ 978 public static boolean isEmpty(Collection coll) { 979 return (coll == null || coll.isEmpty()); 980 } 981 982 /** 983 * Null-safe check if the specified collection is not empty. 984 * <p> 985 * Null returns false. 986 * 987 * @param coll the collection to check, may be null 988 * @return true if non-null and non-empty 989 * @since Commons Collections 3.2 990 */ 991 public static boolean isNotEmpty(Collection coll) { 992 return !CollectionUtils.isEmpty(coll); 993 } 994 995 //----------------------------------------------------------------------- 996 /** 997 * Reverses the order of the given array. 998 * 999 * @param array the array to reverse 1000 */ 1001 public static void reverseArray(Object[] array) { 1002 int i = 0; 1003 int j = array.length - 1; 1004 Object tmp; 1005 1006 while (j > i) { 1007 tmp = array[j]; 1008 array[j] = array[i]; 1009 array[i] = tmp; 1010 j--; 1011 i++; 1012 } 1013 } 1014 1015 private static final int getFreq(final Object obj, final Map freqMap) { 1016 Integer count = (Integer) freqMap.get(obj); 1017 if (count != null) { 1018 return count.intValue(); 1019 } 1020 return 0; 1021 } 1022 1023 /** 1024 * Returns true if no more elements can be added to the Collection. 1025 * <p> 1026 * This method uses the {@link BoundedCollection} interface to determine the 1027 * full status. If the collection does not implement this interface then 1028 * false is returned. 1029 * <p> 1030 * The collection does not have to implement this interface directly. 1031 * If the collection has been decorated using the decorators subpackage 1032 * then these will be removed to access the BoundedCollection. 1033 * 1034 * @param coll the collection to check 1035 * @return true if the BoundedCollection is full 1036 * @throws NullPointerException if the collection is null 1037 */ 1038 public static boolean isFull(Collection coll) { 1039 if (coll == null) { 1040 throw new NullPointerException("The collection must not be null"); 1041 } 1042 if (coll instanceof BoundedCollection) { 1043 return ((BoundedCollection) coll).isFull(); 1044 } 1045 try { 1046 BoundedCollection bcoll = UnmodifiableBoundedCollection.decorateUsing(coll); 1047 return bcoll.isFull(); 1048 1049 } catch (IllegalArgumentException ex) { 1050 return false; 1051 } 1052 } 1053 1054 /** 1055 * Get the maximum number of elements that the Collection can contain. 1056 * <p> 1057 * This method uses the {@link BoundedCollection} interface to determine the 1058 * maximum size. If the collection does not implement this interface then 1059 * -1 is returned. 1060 * <p> 1061 * The collection does not have to implement this interface directly. 1062 * If the collection has been decorated using the decorators subpackage 1063 * then these will be removed to access the BoundedCollection. 1064 * 1065 * @param coll the collection to check 1066 * @return the maximum size of the BoundedCollection, -1 if no maximum size 1067 * @throws NullPointerException if the collection is null 1068 */ 1069 public static int maxSize(Collection coll) { 1070 if (coll == null) { 1071 throw new NullPointerException("The collection must not be null"); 1072 } 1073 if (coll instanceof BoundedCollection) { 1074 return ((BoundedCollection) coll).maxSize(); 1075 } 1076 try { 1077 BoundedCollection bcoll = UnmodifiableBoundedCollection.decorateUsing(coll); 1078 return bcoll.maxSize(); 1079 1080 } catch (IllegalArgumentException ex) { 1081 return -1; 1082 } 1083 } 1084 1085 //----------------------------------------------------------------------- 1086 /** 1087 * Returns a collection containing all the elements in <code>collection</code> 1088 * that are also in <code>retain</code>. The cardinality of an element <code>e</code> 1089 * in the returned collection is the same as the cardinality of <code>e</code> 1090 * in <code>collection</code> unless <code>retain</code> does not contain <code>e</code>, in which 1091 * case the cardinality is zero. This method is useful if you do not wish to modify 1092 * the collection <code>c</code> and thus cannot call <code>c.retainAll(retain);</code>. 1093 * 1094 * @param collection the collection whose contents are the target of the #retailAll operation 1095 * @param retain the collection containing the elements to be retained in the returned collection 1096 * @return a <code>Collection</code> containing all the elements of <code>collection</code> 1097 * that occur at least once in <code>retain</code>. 1098 * @throws NullPointerException if either parameter is null 1099 * @since Commons Collections 3.2 1100 */ 1101 public static Collection retainAll(Collection collection, Collection retain) { 1102 return ListUtils.retainAll(collection, retain); 1103 } 1104 1105 /** 1106 * Removes the elements in <code>remove</code> from <code>collection</code>. That is, this 1107 * method returns a collection containing all the elements in <code>c</code> 1108 * that are not in <code>remove</code>. The cardinality of an element <code>e</code> 1109 * in the returned collection is the same as the cardinality of <code>e</code> 1110 * in <code>collection</code> unless <code>remove</code> contains <code>e</code>, in which 1111 * case the cardinality is zero. This method is useful if you do not wish to modify 1112 * the collection <code>c</code> and thus cannot call <code>collection.removeAll(remove);</code>. 1113 * 1114 * @param collection the collection from which items are removed (in the returned collection) 1115 * @param remove the items to be removed from the returned <code>collection</code> 1116 * @return a <code>Collection</code> containing all the elements of <code>collection</code> except 1117 * any elements that also occur in <code>remove</code>. 1118 * @throws NullPointerException if either parameter is null 1119 * @since Commons Collections 3.2 1120 */ 1121 public static Collection removeAll(Collection collection, Collection remove) { 1122 return ListUtils.retainAll(collection, remove); 1123 } 1124 1125 //----------------------------------------------------------------------- 1126 /** 1127 * Returns a synchronized collection backed by the given collection. 1128 * <p> 1129 * You must manually synchronize on the returned buffer's iterator to 1130 * avoid non-deterministic behavior: 1131 * 1132 * <pre> 1133 * Collection c = CollectionUtils.synchronizedCollection(myCollection); 1134 * synchronized (c) { 1135 * Iterator i = c.iterator(); 1136 * while (i.hasNext()) { 1137 * process (i.next()); 1138 * } 1139 * } 1140 * </pre> 1141 * 1142 * This method uses the implementation in the decorators subpackage. 1143 * 1144 * @param collection the collection to synchronize, must not be null 1145 * @return a synchronized collection backed by the given collection 1146 * @throws IllegalArgumentException if the collection is null 1147 */ 1148 public static Collection synchronizedCollection(Collection collection) { 1149 return SynchronizedCollection.decorate(collection); 1150 } 1151 1152 /** 1153 * Returns an unmodifiable collection backed by the given collection. 1154 * <p> 1155 * This method uses the implementation in the decorators subpackage. 1156 * 1157 * @param collection the collection to make unmodifiable, must not be null 1158 * @return an unmodifiable collection backed by the given collection 1159 * @throws IllegalArgumentException if the collection is null 1160 */ 1161 public static Collection unmodifiableCollection(Collection collection) { 1162 return UnmodifiableCollection.decorate(collection); 1163 } 1164 1165 /** 1166 * Returns a predicated (validating) collection backed by the given collection. 1167 * <p> 1168 * Only objects that pass the test in the given predicate can be added to the collection. 1169 * Trying to add an invalid object results in an IllegalArgumentException. 1170 * It is important not to use the original collection after invoking this method, 1171 * as it is a backdoor for adding invalid objects. 1172 * 1173 * @param collection the collection to predicate, must not be null 1174 * @param predicate the predicate for the collection, must not be null 1175 * @return a predicated collection backed by the given collection 1176 * @throws IllegalArgumentException if the Collection is null 1177 */ 1178 public static Collection predicatedCollection(Collection collection, Predicate predicate) { 1179 return PredicatedCollection.decorate(collection, predicate); 1180 } 1181 1182 /** 1183 * Returns a typed collection backed by the given collection. 1184 * <p> 1185 * Only objects of the specified type can be added to the collection. 1186 * 1187 * @param collection the collection to limit to a specific type, must not be null 1188 * @param type the type of objects which may be added to the collection 1189 * @return a typed collection backed by the specified collection 1190 */ 1191 public static Collection typedCollection(Collection collection, Class type) { 1192 return TypedCollection.decorate(collection, type); 1193 } 1194 1195 /** 1196 * Returns a transformed bag backed by the given collection. 1197 * <p> 1198 * Each object is passed through the transformer as it is added to the 1199 * Collection. It is important not to use the original collection after invoking this 1200 * method, as it is a backdoor for adding untransformed objects. 1201 * 1202 * @param collection the collection to predicate, must not be null 1203 * @param transformer the transformer for the collection, must not be null 1204 * @return a transformed collection backed by the given collection 1205 * @throws IllegalArgumentException if the Collection or Transformer is null 1206 */ 1207 public static Collection transformedCollection(Collection collection, Transformer transformer) { 1208 return TransformedCollection.decorate(collection, transformer); 1209 } 1210 1211 }