From 6c8caea3311ce08b6fa1bd2eb38054494faa2949 Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Sat, 6 Jun 2015 12:00:46 +0000 Subject: [PATCH] [COLLECTIONS-551] Move forAllButLastDo methods, add unmodifiableIterable. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1683897 13f79535-47bb-0310-9956-ffa450edef68 --- .../commons/collections4/CollectionUtils.java | 18 ++---- .../commons/collections4/FluentIterable.java | 10 +++ .../commons/collections4/IterableUtils.java | 62 +++++++++++++++++-- .../commons/collections4/IteratorUtils.java | 31 ++++++++++ .../collections4/CollectionUtilsTest.java | 1 + .../collections4/FluentIterableTest.java | 18 ++++++ .../collections4/IterableUtilsTest.java | 32 ++++++++++ .../collections4/IteratorUtilsTest.java | 32 ++++++++++ 8 files changed, 188 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java b/src/main/java/org/apache/commons/collections4/CollectionUtils.java index 171acc30b..1a12d9f79 100644 --- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java +++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java @@ -708,10 +708,12 @@ public class CollectionUtils { * @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 * @since 4.0 + * @deprecated since 4.1, use {@link IterableUtils#applyForAllButLast(Iterable, Closure)} instead */ + @Deprecated public static > T forAllButLastDo(final Iterable collection, final C closure) { - return collection != null && closure != null ? forAllButLastDo(collection.iterator(), closure) : null; + return closure != null ? IterableUtils.applyForAllButLast(collection, closure) : null; } /** @@ -725,19 +727,11 @@ public class CollectionUtils { * @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 * @since 4.0 + * @deprecated since 4.1, use {@link IteratorUtils#applyForAllButLast(Iterator, Closure)} instead */ + @Deprecated 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; + return closure != null ? IteratorUtils.applyForAllButLast(iterator, closure) : null; } /** diff --git a/src/main/java/org/apache/commons/collections4/FluentIterable.java b/src/main/java/org/apache/commons/collections4/FluentIterable.java index 5b6e72851..2ae931d9a 100644 --- a/src/main/java/org/apache/commons/collections4/FluentIterable.java +++ b/src/main/java/org/apache/commons/collections4/FluentIterable.java @@ -300,6 +300,16 @@ public class FluentIterable implements Iterable { return of(IterableUtils.uniqueIterable(iterable)); } + /** + * Returns a new FluentIterable whose iterator will return an unmodifiable + * view of this iterable. + * + * @return a new iterable, providing an unmodifiable view of this iterable + */ + public FluentIterable unmodifiable() { + return of(IterableUtils.unmodifiableIterable(iterable)); + } + /** * Returns a new FluentIterable whose iterator will traverse * the elements of this iterable and the other iterable in diff --git a/src/main/java/org/apache/commons/collections4/IterableUtils.java b/src/main/java/org/apache/commons/collections4/IterableUtils.java index 9a04619bf..91ad37260 100644 --- a/src/main/java/org/apache/commons/collections4/IterableUtils.java +++ b/src/main/java/org/apache/commons/collections4/IterableUtils.java @@ -235,7 +235,7 @@ public class IterableUtils { * Returns a view of the given iterable that only contains elements matching * the provided predicate. *

- * The returned iterable's iterator does not supports {@code remove()}. + * The returned iterable's iterator does not support {@code remove()}. * * @param the element type * @param iterable the iterable to filter, may be null @@ -397,7 +397,7 @@ public class IterableUtils { * @param the input element type * @param the output element type * @param iterable the iterable to transform, may be null - * @param transformer the transformer , must not be null + * @param transformer the transformer, must not be null * @return a transformed view of the specified iterable * @throws NullPointerException if transformer is null */ @@ -421,10 +421,10 @@ public class IterableUtils { /** * Returns a unique view of the given iterable. *

- * The returned iterable's iterator does not supports {@code remove()}. + * The returned iterable's iterator does not support {@code remove()}. * * @param the element type - * @param iterable the iterable to transform, may be null + * @param iterable the iterable to use, may be null * @return a unique view of the specified iterable */ public static Iterable uniqueIterable(final Iterable iterable) { @@ -436,6 +436,44 @@ public class IterableUtils { }; } + // Unmodifiable + // ---------------------------------------------------------------------- + + /** + * Returns an unmodifiable view of the given iterable. + *

+ * The returned iterable's iterator does not support {@code remove()}. + * + * @param the element type + * @param iterable the iterable to use, may be null + * @return an unmodifiable view of the specified iterable + */ + public static Iterable unmodifiableIterable(final Iterable iterable) { + if (iterable instanceof UnmodifiableIterable) { + return iterable; + } + @SuppressWarnings("unchecked") // safe + final Iterable it = iterable != null ? iterable : EMPTY_ITERABLE; + return new UnmodifiableIterable(it); + } + + /** + * Inner class to distinguish unmodifiable instances. + */ + private static final class UnmodifiableIterable extends FluentIterable { + private final Iterable unmodifiable; + + public UnmodifiableIterable(final Iterable iterable) { + super(); + this.unmodifiable = iterable; + } + + @Override + public Iterator iterator() { + return IteratorUtils.unmodifiableIterator(unmodifiable.iterator()); + } + } + // Zipping // ---------------------------------------------------------------------- @@ -515,6 +553,22 @@ public class IterableUtils { IteratorUtils.apply(emptyIteratorIfNull(iterable), closure); } + /** + * Executes the given closure on each but the last element in the iterable. + *

+ * If the input iterable is null no change is made. + * + * @param the type of object the {@link Iterable} contains + * @param the closure type + * @param iterable the iterable to get the input from, may be null + * @param closure the closure to perform, may not be null + * @return the last element in the iterable, or null if iterable is null or empty + */ + public static > E applyForAllButLast(final Iterable iterable, + final C closure) { + return IteratorUtils.applyForAllButLast(emptyIteratorIfNull(iterable), closure); + } + /** * Finds the first element in the given iterable which matches the given predicate. *

diff --git a/src/main/java/org/apache/commons/collections4/IteratorUtils.java b/src/main/java/org/apache/commons/collections4/IteratorUtils.java index b3b1be0ff..99c799355 100644 --- a/src/main/java/org/apache/commons/collections4/IteratorUtils.java +++ b/src/main/java/org/apache/commons/collections4/IteratorUtils.java @@ -1251,6 +1251,37 @@ public class IteratorUtils { } } + /** + * Executes the given closure on each but the last element in the iterator. + *

+ * If the input iterator is null no change is made. + * + * @param the type of object the {@link Iterator} contains + * @param the closure type + * @param iterator the iterator to get the input from, may be null + * @param closure the closure to perform, may not be null + * @return the last element in the iterator, or null if iterator is null or empty + * @throws NullPointerException if closure is null + * @since 4.1 + */ + public static > E applyForAllButLast(final Iterator iterator, + final C closure) { + if (closure == null) { + throw new NullPointerException("Closure must not be null."); + } + if (iterator != null) { + while (iterator.hasNext()) { + final E element = iterator.next(); + if (iterator.hasNext()) { + closure.execute(element); + } else { + return element; + } + } + } + return null; + } + /** * Finds the first element in the given iterator which matches the given predicate. *

diff --git a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java index 931ea8f2e..8c9e8f49e 100644 --- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java @@ -712,6 +712,7 @@ public class CollectionUtilsTest extends MockTestCase { } @Test + @Deprecated public void forAllButLastDoIterator() { final Closure> testClosure = ClosureUtils.invokerClosure("clear"); final Collection> col = new ArrayList>(); diff --git a/src/test/java/org/apache/commons/collections4/FluentIterableTest.java b/src/test/java/org/apache/commons/collections4/FluentIterableTest.java index 9d986f17e..ac7c38e1e 100644 --- a/src/test/java/org/apache/commons/collections4/FluentIterableTest.java +++ b/src/test/java/org/apache/commons/collections4/FluentIterableTest.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -282,6 +283,23 @@ public class FluentIterableTest { assertEquals(0, result.size()); } + @Test + public void unmodifiable() { + FluentIterable iterable1 = FluentIterable.of(iterableA).unmodifiable(); + Iterator it = iterable1.iterator(); + assertEquals(1, it.next().intValue()); + try { + it.remove(); + fail("expecting UnsupportedOperationException"); + } catch (UnsupportedOperationException ise) { + // expected + } + + // calling unmodifiable on an already unmodifiable iterable shall return the same instance + FluentIterable iterable2 = iterable1.unmodifiable(); + assertSame(iterable1, iterable2); + } + @Test public void zip() { List result = FluentIterable.of(iterableOdd).zip(iterableEven).toList(); diff --git a/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java b/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java index 5dea179b6..3cdf421b3 100644 --- a/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java @@ -133,6 +133,38 @@ public class IterableUtilsTest { IterableUtils.apply(col, testClosure); } + @Test + public void applyForAllButLast() { + final List listA = new ArrayList(); + listA.add(1); + + final List listB = new ArrayList(); + listB.add(2); + + final Closure> testClosure = ClosureUtils.invokerClosure("clear"); + final Collection> col = new ArrayList>(); + col.add(listA); + col.add(listB); + List last = IterableUtils.applyForAllButLast(col, testClosure); + assertTrue(listA.isEmpty() && !listB.isEmpty()); + assertSame(listB, last); + + try { + IterableUtils.apply(col, null); + fail("expecting NullPointerException"); + } catch (NullPointerException npe) { + // expected + } + + IterableUtils.apply(null, testClosure); + + // null should be OK + col.add(null); + col.add(null); + last = IterableUtils.applyForAllButLast(col, testClosure); + assertNull(last); + } + @Test public void containsWithEquator() { final List base = new ArrayList(); diff --git a/src/test/java/org/apache/commons/collections4/IteratorUtilsTest.java b/src/test/java/org/apache/commons/collections4/IteratorUtilsTest.java index e72b8e12a..913ed56d5 100644 --- a/src/test/java/org/apache/commons/collections4/IteratorUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/IteratorUtilsTest.java @@ -997,6 +997,38 @@ public class IteratorUtilsTest { IteratorUtils.apply(col.iterator(), testClosure); } + @Test + public void applyForAllButLast() { + final List listA = new ArrayList(); + listA.add(1); + + final List listB = new ArrayList(); + listB.add(2); + + final Closure> testClosure = ClosureUtils.invokerClosure("clear"); + final Collection> col = new ArrayList>(); + col.add(listA); + col.add(listB); + List last = IteratorUtils.applyForAllButLast(col.iterator(), testClosure); + assertTrue(listA.isEmpty() && !listB.isEmpty()); + assertSame(listB, last); + + try { + IteratorUtils.apply(col.iterator(), null); + fail("expecting NullPointerException"); + } catch (NullPointerException npe) { + // expected + } + + IteratorUtils.apply(null, testClosure); + + // null should be OK + col.add(null); + col.add(null); + last = IteratorUtils.applyForAllButLast(col.iterator(), testClosure); + assertNull(last); + } + @Test public void find() { Predicate testPredicate = equalPredicate((Number) 4);