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