Tree traversal with a TreeListIterator will not be affected anymore by
the removal of an element directly after a call to previous().
diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java
index f7b6d605b..dbd31b28b 100644
--- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java
+++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java
@@ -694,6 +694,47 @@ public class CollectionUtils {
return closure;
}
+ /**
+ * Executes the given closure on each but the last element in the collection.
+ *
+ * If the input collection or closure is null, there is no change made.
+ *
+ * @param the type of object the {@link Collection} contains
+ * @param the closure type
+ * @param collection the collection to get the input from, may be null
+ * @param closure the closure to perform, may be null
+ * @return the last element in the collection, or null if either collection or closure is null
+ */
+ public static > T forAllButLastDo(final Collection collection,
+ final C closure) {
+ return collection != null && closure != null ? forAllButLastDo(collection.iterator(), closure) : null;
+ }
+
+ /**
+ * Executes the given closure on each but the last element in the collection.
+ *
+ * If the input collection or closure is null, there is no change made.
+ *
+ * @param the type of object the {@link Collection} contains
+ * @param the closure type
+ * @param iterator the iterator to get the input from, may be null
+ * @param closure the closure to perform, may be null
+ * @return the last element in the collection, or null if either iterator or closure is null
+ */
+ public static > T forAllButLastDo(final Iterator iterator, final C closure) {
+ if (iterator != null && closure != null) {
+ while (iterator.hasNext()) {
+ final T element = iterator.next();
+ if (iterator.hasNext()) {
+ closure.execute(element);
+ } else {
+ return element;
+ }
+ }
+ }
+ return null;
+ }
+
/**
* Filter the collection by applying a Predicate to each element. If the
* predicate returns false, remove the element.
diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
index 1768e611c..a84c51bd5 100644
--- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
@@ -663,6 +663,61 @@ public class CollectionUtilsTest extends MockTestCase {
CollectionUtils.forAllDo(col, testClosure);
}
+ @Test
+ public void forAllButLastDoCollection() {
+ final Closure> testClosure = ClosureUtils.invokerClosure("clear");
+ final Collection> col = new ArrayList>();
+ col.add(collectionA);
+ col.add(collectionB);
+ List extends Number> lastElement = CollectionUtils.forAllButLastDo(col, testClosure);
+ assertSame(lastElement, collectionB);
+ assertTrue(collectionA.isEmpty() && !collectionB.isEmpty());
+
+ col.clear();
+ col.add(collectionB);
+ lastElement = CollectionUtils.forAllButLastDo(col, testClosure);
+ assertSame(lastElement, collectionB);
+ assertTrue(!collectionB.isEmpty() );
+
+ col.clear();
+ lastElement = CollectionUtils.forAllButLastDo(col, testClosure);
+ assertNull(lastElement);
+
+ Collection strings = Arrays.asList(new String[]{"a", "b", "c"});
+ final StringBuffer result = new StringBuffer();
+ result.append(CollectionUtils.forAllButLastDo(strings, new Closure() {
+ public void execute(String input) {
+ result.append(input+";");
+ }
+ }));
+ assertEquals("a;b;c", result.toString());
+
+ Collection oneString = Arrays.asList(new String[]{"a"});
+ final StringBuffer resultOne = new StringBuffer();
+ resultOne.append(CollectionUtils.forAllButLastDo(oneString, new Closure() {
+ public void execute(String input) {
+ resultOne.append(input+";");
+ }
+ }));
+ assertEquals("a", resultOne.toString());
+ assertNull(CollectionUtils.forAllButLastDo(strings, null));
+ assertNull(CollectionUtils.forAllButLastDo((Collection>) null, null));
+ }
+
+ @Test
+ public void forAllButLastDoIterator() {
+ final Closure> testClosure = ClosureUtils.invokerClosure("clear");
+ final Collection> col = new ArrayList>();
+ col.add(collectionA);
+ col.add(collectionB);
+ List extends Number> lastElement = CollectionUtils.forAllButLastDo(col.iterator(), testClosure);
+ assertSame(lastElement, collectionB);
+ assertTrue(collectionA.isEmpty() && !collectionB.isEmpty());
+
+ assertNull(CollectionUtils.forAllButLastDo(col.iterator(), null));
+ assertNull(CollectionUtils.forAllButLastDo((Collection>) null, null));
+ }
+
@Test
public void getFromMap() {
// Unordered map, entries exist