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