Clarify null argument behavior of IterableUtils and FluentIterable: decorators do not accept null values, whereas utility methods are null-safe wrt Iterable instances.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1684147 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a049083c8f
commit
f4693f0adf
|
@ -117,15 +117,13 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
* corresponding input iterator supports it.
|
* corresponding input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <T> the element type
|
* @param <T> the element type
|
||||||
* @param iterable the iterable to wrap into a FluentIterable, may be null
|
* @param iterable the iterable to wrap into a FluentIterable, may not be null
|
||||||
* @return a new FluentIterable wrapping the provided iterable
|
* @return a new FluentIterable wrapping the provided iterable
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
*/
|
*/
|
||||||
public static <T> FluentIterable<T> of(final Iterable<T> iterable) {
|
public static <T> FluentIterable<T> of(final Iterable<T> iterable) {
|
||||||
if (iterable == null) {
|
IterableUtils.checkNotNull(iterable);
|
||||||
@SuppressWarnings("unchecked")
|
if (iterable instanceof FluentIterable<?>) {
|
||||||
final FluentIterable<T> empty = IterableUtils.EMPTY_ITERABLE;
|
|
||||||
return empty;
|
|
||||||
} else if (iterable instanceof FluentIterable<?>) {
|
|
||||||
return (FluentIterable<T>) iterable;
|
return (FluentIterable<T>) iterable;
|
||||||
} else {
|
} else {
|
||||||
return new FluentIterable<T>(iterable);
|
return new FluentIterable<T>(iterable);
|
||||||
|
@ -169,11 +167,10 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
* Returns a new FluentIterable whose iterator will first traverse
|
* Returns a new FluentIterable whose iterator will first traverse
|
||||||
* the elements of the current iterable, followed by the elements
|
* the elements of the current iterable, followed by the elements
|
||||||
* of the provided iterable.
|
* of the provided iterable.
|
||||||
* <p>
|
|
||||||
* A <code>null</code> iterable will be treated as an empty iterable.
|
|
||||||
*
|
*
|
||||||
* @param other the other iterable to combine, may be null
|
* @param other the other iterable to combine, may not be null
|
||||||
* @return a new iterable, combining this iterable with other
|
* @return a new iterable, combining this iterable with other
|
||||||
|
* @throws NullPointerException if other is null
|
||||||
*/
|
*/
|
||||||
public FluentIterable<E> append(final Iterable<? extends E> other) {
|
public FluentIterable<E> append(final Iterable<? extends E> other) {
|
||||||
return of(IterableUtils.chainedIterable(iterable, other));
|
return of(IterableUtils.chainedIterable(iterable, other));
|
||||||
|
@ -191,11 +188,10 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
* <p>
|
* <p>
|
||||||
* The returned iterable will traverse the elements in the following
|
* The returned iterable will traverse the elements in the following
|
||||||
* order: [1, 2, 3, 4, 5, 6, 7, 8]
|
* order: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
* <p>
|
|
||||||
* A <code>null</code> iterable will be treated as an empty iterable.
|
|
||||||
*
|
*
|
||||||
* @param other the other iterable to collate, may be null
|
* @param other the other iterable to collate, may not be null
|
||||||
* @return a new iterable, collating this iterable with the other in natural order
|
* @return a new iterable, collating this iterable with the other in natural order
|
||||||
|
* @throws NullPointerException if other is null
|
||||||
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator}
|
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator}
|
||||||
*/
|
*/
|
||||||
public FluentIterable<E> collate(final Iterable<? extends E> other) {
|
public FluentIterable<E> collate(final Iterable<? extends E> other) {
|
||||||
|
@ -215,13 +211,12 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
* <p>
|
* <p>
|
||||||
* The returned iterable will traverse the elements in the following
|
* The returned iterable will traverse the elements in the following
|
||||||
* order: [8, 7, 6, 5, 4, 3, 2, 1]
|
* order: [8, 7, 6, 5, 4, 3, 2, 1]
|
||||||
* <p>
|
|
||||||
* A <code>null</code> iterable will be treated as an empty iterable.
|
|
||||||
*
|
*
|
||||||
* @param comparator the comparator to define an ordering, may be null,
|
* @param comparator the comparator to define an ordering, may be null,
|
||||||
* in which case natural ordering will be used
|
* in which case natural ordering will be used
|
||||||
* @param other the other iterable to collate, may be null
|
* @param other the other iterable to collate, may not be null
|
||||||
* @return a new iterable, collating this iterable with the other in natural order
|
* @return a new iterable, collating this iterable with the other in natural order
|
||||||
|
* @throws NullPointerException if other is null
|
||||||
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator}
|
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator}
|
||||||
*/
|
*/
|
||||||
public FluentIterable<E> collate(final Iterable<? extends E> other,
|
public FluentIterable<E> collate(final Iterable<? extends E> other,
|
||||||
|
@ -341,8 +336,9 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
* the elements of this iterable and the other iterable in
|
* the elements of this iterable and the other iterable in
|
||||||
* alternating order.
|
* alternating order.
|
||||||
*
|
*
|
||||||
* @param other the other iterable to interleave
|
* @param other the other iterable to interleave, may not be null
|
||||||
* @return a new iterable, interleaving this iterable with others
|
* @return a new iterable, interleaving this iterable with others
|
||||||
|
* @throws NullPointerException if other is null
|
||||||
*/
|
*/
|
||||||
public FluentIterable<E> zip(final Iterable<? extends E> other) {
|
public FluentIterable<E> zip(final Iterable<? extends E> other) {
|
||||||
return of(IterableUtils.zippingIterable(iterable, other));
|
return of(IterableUtils.zippingIterable(iterable, other));
|
||||||
|
@ -353,15 +349,12 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
* the elements of this iterable and the other iterables in
|
* the elements of this iterable and the other iterables in
|
||||||
* alternating order.
|
* alternating order.
|
||||||
*
|
*
|
||||||
* @param others the iterables to interleave
|
* @param others the iterables to interleave, may not be null
|
||||||
* @return a new iterable, interleaving this iterable with others
|
* @return a new iterable, interleaving this iterable with others
|
||||||
|
* @throws NullPointerException if either of the provided iterables is null
|
||||||
*/
|
*/
|
||||||
public FluentIterable<E> zip(final Iterable<? extends E>... others) {
|
public FluentIterable<E> zip(final Iterable<? extends E>... others) {
|
||||||
@SuppressWarnings("unchecked")
|
return of(IterableUtils.zippingIterable(iterable, others));
|
||||||
Iterable<E>[] iterables = new Iterable[1 + others.length];
|
|
||||||
iterables[0] = iterable;
|
|
||||||
System.arraycopy(others, 0, iterables, 1, others.length);
|
|
||||||
return of(IterableUtils.zippingIterable(iterables));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convenience methods
|
// convenience methods
|
||||||
|
|
|
@ -32,10 +32,17 @@ import org.apache.commons.collections4.iterators.UniqueFilterIterator;
|
||||||
/**
|
/**
|
||||||
* Provides utility methods and decorators for {@link Iterable} instances.
|
* Provides utility methods and decorators for {@link Iterable} instances.
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Note</b>: by design, all provided utility methods will treat a {@code null}
|
* <b>Note</b>: this util class has been designed for fail-fast argument checking.
|
||||||
* {@link Iterable} parameters the same way as an empty iterable. All other required
|
* <ul>
|
||||||
* parameters which are null, e.g. a {@link Predicate}, will result in a
|
* <li>
|
||||||
* {@link NullPointerException}.
|
* all decorator methods are <b>NOT</b> null-safe wrt the provided Iterable argument, i.e.
|
||||||
|
* they will throw a {@link NullPointerException} if a null Iterable is passed as argument.
|
||||||
|
* <li>
|
||||||
|
* all other utility methods are null-safe wrt the provided Iterable argument, i.e. they will
|
||||||
|
* treat a null Iterable the same way as an empty one. Other arguments which are null,
|
||||||
|
* e.g. a {@link Predicate}, will result in a {@link NullPointerException}. Exception: passing
|
||||||
|
* a null {@link Comparator} is equivalent to a Comparator with natural ordering.
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
|
@ -83,9 +90,10 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param a the first iterable
|
* @param a the first iterable, may not be null
|
||||||
* @param b the second iterable
|
* @param b the second iterable, may not be null
|
||||||
* @return a new iterable, combining the provided iterables
|
* @return a new iterable, combining the provided iterables
|
||||||
|
* @throws NullPointerException if either a or b is null
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
|
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
|
||||||
|
@ -104,10 +112,11 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param a the first iterable
|
* @param a the first iterable, may not be null
|
||||||
* @param b the second iterable
|
* @param b the second iterable, may not be null
|
||||||
* @param c the third iterable
|
* @param c the third iterable, may not be null
|
||||||
* @return a new iterable, combining the provided iterables
|
* @return a new iterable, combining the provided iterables
|
||||||
|
* @throws NullPointerException if either of the provided iterables is null
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
|
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
|
||||||
|
@ -127,11 +136,12 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param a the first iterable
|
* @param a the first iterable, may not be null
|
||||||
* @param b the second iterable
|
* @param b the second iterable, may not be null
|
||||||
* @param c the third iterable
|
* @param c the third iterable, may not be null
|
||||||
* @param d the fourth iterable
|
* @param d the fourth iterable, may not be null
|
||||||
* @return a new iterable, combining the provided iterables
|
* @return a new iterable, combining the provided iterables
|
||||||
|
* @throws NullPointerException if either of the provided iterables is null
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
|
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a,
|
||||||
|
@ -152,10 +162,12 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterables the iterables to combine
|
* @param iterables the iterables to combine, may not be null
|
||||||
* @return a new iterable, combining the provided iterables
|
* @return a new iterable, combining the provided iterables
|
||||||
|
* @throws NullPointerException if either of the provided iterables is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E>... iterables) {
|
public static <E> Iterable<E> chainedIterable(final Iterable<? extends E>... iterables) {
|
||||||
|
checkNotNull(iterables);
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
|
@ -165,7 +177,7 @@ public class IterableUtils {
|
||||||
if (count > iterables.length) {
|
if (count > iterables.length) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return emptyIteratorIfNull(iterables[count - 1]);
|
return iterables[count - 1].iterator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -184,18 +196,18 @@ public class IterableUtils {
|
||||||
* corresponding input iterator supports it.
|
* corresponding input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param a the first iterable, may be null
|
* @param a the first iterable, may not be null
|
||||||
* @param b the second iterable, may be null
|
* @param b the second iterable, may not be null
|
||||||
* @return a filtered view on the specified iterable
|
* @return a filtered view on the specified iterable
|
||||||
|
* @throws NullPointerException if either of the provided iterables is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> collatedIterable(final Iterable<? extends E> a,
|
public static <E> Iterable<E> collatedIterable(final Iterable<? extends E> a,
|
||||||
final Iterable<? extends E> b) {
|
final Iterable<? extends E> b) {
|
||||||
|
checkNotNull(a, b);
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return IteratorUtils.collatedIterator(null,
|
return IteratorUtils.collatedIterator(null, a.iterator(), b.iterator());
|
||||||
emptyIteratorIfNull(a),
|
|
||||||
emptyIteratorIfNull(b));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -211,19 +223,19 @@ public class IterableUtils {
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param comparator the comparator defining an ordering over the elements,
|
* @param comparator the comparator defining an ordering over the elements,
|
||||||
* may be null, in which case natural ordering will be used
|
* may be null, in which case natural ordering will be used
|
||||||
* @param a the first iterable, may be null
|
* @param a the first iterable, may not be null
|
||||||
* @param b the second iterable, may be null
|
* @param b the second iterable, may not be null
|
||||||
* @return a filtered view on the specified iterable
|
* @return a filtered view on the specified iterable
|
||||||
|
* @throws NullPointerException if either of the provided iterables is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> collatedIterable(final Comparator<? super E> comparator,
|
public static <E> Iterable<E> collatedIterable(final Comparator<? super E> comparator,
|
||||||
final Iterable<? extends E> a,
|
final Iterable<? extends E> a,
|
||||||
final Iterable<? extends E> b) {
|
final Iterable<? extends E> b) {
|
||||||
|
checkNotNull(a, b);
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return IteratorUtils.collatedIterator(comparator,
|
return IteratorUtils.collatedIterator(comparator, a.iterator(), b.iterator());
|
||||||
emptyIteratorIfNull(a),
|
|
||||||
emptyIteratorIfNull(b));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -238,17 +250,17 @@ public class IterableUtils {
|
||||||
* The returned iterable's iterator does not support {@code remove()}.
|
* The returned iterable's iterator does not support {@code remove()}.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterable the iterable to filter, may be null
|
* @param iterable the iterable to filter, may not be null
|
||||||
* @param predicate the predicate used to filter elements, may not be null
|
* @param predicate the predicate used to filter elements, may not be null
|
||||||
* @return a filtered view on the specified iterable
|
* @return a filtered view on the specified iterable
|
||||||
* @throws NullPointerException if predicate is null
|
* @throws NullPointerException if either iterable or predicate is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> filteredIterable(final Iterable<E> iterable,
|
public static <E> Iterable<E> filteredIterable(final Iterable<E> iterable,
|
||||||
final Predicate<? super E> predicate) {
|
final Predicate<? super E> predicate) {
|
||||||
|
checkNotNull(iterable);
|
||||||
if (predicate == null) {
|
if (predicate == null) {
|
||||||
throw new NullPointerException("Predicate must not be null.");
|
throw new NullPointerException("Predicate must not be null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
|
@ -268,12 +280,14 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterable the iterable to limit, may be null
|
* @param iterable the iterable to limit, may not be null
|
||||||
* @param maxSize the maximum number of elements, must not be negative
|
* @param maxSize the maximum number of elements, must not be negative
|
||||||
* @return a bounded view on the specified iterable
|
* @return a bounded view on the specified iterable
|
||||||
* @throws IllegalArgumentException if maxSize is negative
|
* @throws IllegalArgumentException if maxSize is negative
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> boundedIterable(final Iterable<E> iterable, final long maxSize) {
|
public static <E> Iterable<E> boundedIterable(final Iterable<E> iterable, final long maxSize) {
|
||||||
|
checkNotNull(iterable);
|
||||||
if (maxSize < 0) {
|
if (maxSize < 0) {
|
||||||
throw new IllegalArgumentException("MaxSize parameter must not be negative.");
|
throw new IllegalArgumentException("MaxSize parameter must not be negative.");
|
||||||
}
|
}
|
||||||
|
@ -281,7 +295,7 @@ public class IterableUtils {
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return IteratorUtils.boundedIterator(emptyIteratorIfNull(iterable), maxSize);
|
return IteratorUtils.boundedIterator(iterable.iterator(), maxSize);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -300,24 +314,22 @@ public class IterableUtils {
|
||||||
* is empty.
|
* is empty.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterable the iterable to loop, may be null
|
* @param iterable the iterable to loop, may not be null
|
||||||
* @return a view of the iterable, providing an infinite loop over its elements
|
* @return a view of the iterable, providing an infinite loop over its elements
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> loopingIterable(final Iterable<E> iterable) {
|
public static <E> Iterable<E> loopingIterable(final Iterable<E> iterable) {
|
||||||
|
checkNotNull(iterable);
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return new LazyIteratorChain<E>() {
|
return new LazyIteratorChain<E>() {
|
||||||
@Override
|
@Override
|
||||||
protected Iterator<? extends E> nextIterator(int count) {
|
protected Iterator<? extends E> nextIterator(int count) {
|
||||||
if (iterable != null) {
|
if (IterableUtils.isEmpty(iterable)) {
|
||||||
if (IterableUtils.isEmpty(iterable)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return iterable.iterator();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
return null;
|
||||||
|
} else {
|
||||||
|
return iterable.iterator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -339,18 +351,19 @@ public class IterableUtils {
|
||||||
* provided iterable is a {@link List} instance.
|
* provided iterable is a {@link List} instance.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterable the iterable to use, may be null
|
* @param iterable the iterable to use, may not be null
|
||||||
* @return a reversed view of the specified iterable
|
* @return a reversed view of the specified iterable
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
* @see ReverseListIterator
|
* @see ReverseListIterator
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> reversedIterable(final Iterable<E> iterable) {
|
public static <E> Iterable<E> reversedIterable(final Iterable<E> iterable) {
|
||||||
|
checkNotNull(iterable);
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
final List<E> list = (iterable instanceof List<?>) ?
|
final List<E> list = (iterable instanceof List<?>) ?
|
||||||
(List<E>) iterable :
|
(List<E>) iterable :
|
||||||
IteratorUtils.toList(emptyIteratorIfNull(iterable));
|
IteratorUtils.toList(iterable.iterator());
|
||||||
|
|
||||||
return new ReverseListIterator<E>(list);
|
return new ReverseListIterator<E>(list);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -366,12 +379,14 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterable the iterable to use, may be null
|
* @param iterable the iterable to use, may not be null
|
||||||
* @param elementsToSkip the number of elements to skip from the start, must not be negative
|
* @param elementsToSkip the number of elements to skip from the start, must not be negative
|
||||||
* @return a view of the specified iterable, skipping the first N elements
|
* @return a view of the specified iterable, skipping the first N elements
|
||||||
* @throws IllegalArgumentException if elementsToSkip is negative
|
* @throws IllegalArgumentException if elementsToSkip is negative
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> skippingIterable(final Iterable<E> iterable, final long elementsToSkip) {
|
public static <E> Iterable<E> skippingIterable(final Iterable<E> iterable, final long elementsToSkip) {
|
||||||
|
checkNotNull(iterable);
|
||||||
if (elementsToSkip < 0) {
|
if (elementsToSkip < 0) {
|
||||||
throw new IllegalArgumentException("ElementsToSkip parameter must not be negative.");
|
throw new IllegalArgumentException("ElementsToSkip parameter must not be negative.");
|
||||||
}
|
}
|
||||||
|
@ -379,7 +394,7 @@ public class IterableUtils {
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return IteratorUtils.skippingIterator(emptyIteratorIfNull(iterable), elementsToSkip);
|
return IteratorUtils.skippingIterator(iterable.iterator(), elementsToSkip);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -396,21 +411,21 @@ public class IterableUtils {
|
||||||
*
|
*
|
||||||
* @param <I> the input element type
|
* @param <I> the input element type
|
||||||
* @param <O> the output element type
|
* @param <O> the output element type
|
||||||
* @param iterable the iterable to transform, may be null
|
* @param iterable the iterable to transform, may not 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
|
* @return a transformed view of the specified iterable
|
||||||
* @throws NullPointerException if transformer is null
|
* @throws NullPointerException if either iterable or transformer is null
|
||||||
*/
|
*/
|
||||||
public static <I, O> Iterable<O> transformedIterable(final Iterable<I> iterable,
|
public static <I, O> Iterable<O> transformedIterable(final Iterable<I> iterable,
|
||||||
final Transformer<? super I, ? extends O> transformer) {
|
final Transformer<? super I, ? extends O> transformer) {
|
||||||
|
checkNotNull(iterable);
|
||||||
if (transformer == null) {
|
if (transformer == null) {
|
||||||
throw new NullPointerException("Transformer must not be null.");
|
throw new NullPointerException("Transformer must not be null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FluentIterable<O>() {
|
return new FluentIterable<O>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<O> iterator() {
|
public Iterator<O> iterator() {
|
||||||
return IteratorUtils.transformedIterator(emptyIteratorIfNull(iterable), transformer);
|
return IteratorUtils.transformedIterator(iterable.iterator(), transformer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -424,14 +439,16 @@ public class IterableUtils {
|
||||||
* The returned iterable's iterator does not support {@code remove()}.
|
* The returned iterable's iterator does not support {@code remove()}.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterable the iterable to use, may be null
|
* @param iterable the iterable to use, may not be null
|
||||||
* @return a unique view of the specified iterable
|
* @return a unique view of the specified iterable
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> uniqueIterable(final Iterable<E> iterable) {
|
public static <E> Iterable<E> uniqueIterable(final Iterable<E> iterable) {
|
||||||
|
checkNotNull(iterable);
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return new UniqueFilterIterator<E>(emptyIteratorIfNull(iterable));
|
return new UniqueFilterIterator<E>(iterable.iterator());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -445,14 +462,16 @@ public class IterableUtils {
|
||||||
* The returned iterable's iterator does not support {@code remove()}.
|
* The returned iterable's iterator does not support {@code remove()}.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterable the iterable to use, may be null
|
* @param iterable the iterable to use, may not be null
|
||||||
* @return an unmodifiable view of the specified iterable
|
* @return an unmodifiable view of the specified iterable
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> unmodifiableIterable(final Iterable<E> iterable) {
|
public static <E> Iterable<E> unmodifiableIterable(final Iterable<E> iterable) {
|
||||||
|
checkNotNull(iterable);
|
||||||
if (iterable instanceof UnmodifiableIterable<?>) {
|
if (iterable instanceof UnmodifiableIterable<?>) {
|
||||||
return iterable;
|
return iterable;
|
||||||
}
|
}
|
||||||
return new UnmodifiableIterable<E>(emptyIfNull(iterable));
|
return new UnmodifiableIterable<E>(iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -486,14 +505,21 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param a the first iterable
|
* @param a the first iterable, may not be null
|
||||||
* @param b the second iterable
|
* @param b the second iterable, may not be null
|
||||||
* @return a new iterable, interleaving the provided iterables
|
* @return a new iterable, interleaving the provided iterables
|
||||||
|
* @throws NullPointerException if either a or b is null
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> Iterable<E> zippingIterable(final Iterable<? extends E> a,
|
public static <E> Iterable<E> zippingIterable(final Iterable<? extends E> a,
|
||||||
final Iterable<? extends E> b) {
|
final Iterable<? extends E> b) {
|
||||||
return zippingIterable(new Iterable[] {a, b});
|
checkNotNull(a);
|
||||||
|
checkNotNull(b);
|
||||||
|
return new FluentIterable<E>() {
|
||||||
|
@Override
|
||||||
|
public Iterator<E> iterator() {
|
||||||
|
return IteratorUtils.zippingIterator(a.iterator(), b.iterator());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -507,17 +533,22 @@ public class IterableUtils {
|
||||||
* input iterator supports it.
|
* input iterator supports it.
|
||||||
*
|
*
|
||||||
* @param <E> the element type
|
* @param <E> the element type
|
||||||
* @param iterables the array of iterables to interleave
|
* @param iterables the array of iterables to interleave, may not be null
|
||||||
* @return a new iterable, interleaving the provided iterables
|
* @return a new iterable, interleaving the provided iterables
|
||||||
|
* @throws NullPointerException if either of the provided iterables is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> zippingIterable(final Iterable<? extends E>... iterables) {
|
public static <E> Iterable<E> zippingIterable(final Iterable<? extends E> first,
|
||||||
|
final Iterable<? extends E>... others) {
|
||||||
|
checkNotNull(first);
|
||||||
|
checkNotNull(others);
|
||||||
return new FluentIterable<E>() {
|
return new FluentIterable<E>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked") // safe
|
||||||
Iterator<? extends E>[] iterators = new Iterator[iterables.length];
|
Iterator<? extends E>[] iterators = new Iterator[others.length + 1];
|
||||||
for (int i = 0; i < iterables.length; i++) {
|
iterators[0] = first.iterator();
|
||||||
iterators[i] = emptyIteratorIfNull(iterables[i]);
|
for (int i = 0; i < others.length; i++) {
|
||||||
|
iterators[i + 1] = others[i].iterator();
|
||||||
}
|
}
|
||||||
return IteratorUtils.zippingIterator(iterators);
|
return IteratorUtils.zippingIterator(iterators);
|
||||||
}
|
}
|
||||||
|
@ -539,18 +570,6 @@ public class IterableUtils {
|
||||||
return iterable == null ? IterableUtils.<E>emptyIterable() : iterable;
|
return iterable == null ? IterableUtils.<E>emptyIterable() : iterable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an empty iterator if the argument is <code>null</code>,
|
|
||||||
* or {@code iterable.iterator()} otherwise.
|
|
||||||
*
|
|
||||||
* @param <E> the element type
|
|
||||||
* @param iterable the iterable, possibly <code>null</code>
|
|
||||||
* @return an empty iterator if the argument is <code>null</code>
|
|
||||||
*/
|
|
||||||
private static <E> Iterator<E> emptyIteratorIfNull(final Iterable<E> iterable) {
|
|
||||||
return iterable != null ? iterable.iterator() : IteratorUtils.<E>emptyIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the closure to each element of the provided iterable.
|
* Applies the closure to each element of the provided iterable.
|
||||||
*
|
*
|
||||||
|
@ -639,7 +658,7 @@ public class IterableUtils {
|
||||||
if (predicate == null) {
|
if (predicate == null) {
|
||||||
throw new NullPointerException("Predicate must not be null.");
|
throw new NullPointerException("Predicate must not be null.");
|
||||||
}
|
}
|
||||||
return size(filteredIterable(input, predicate));
|
return size(filteredIterable(emptyIfNull(input), predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -716,7 +735,7 @@ public class IterableUtils {
|
||||||
if (iterable instanceof Bag<?>) {
|
if (iterable instanceof Bag<?>) {
|
||||||
return ((Bag<E>) iterable).getCount(obj);
|
return ((Bag<E>) iterable).getCount(obj);
|
||||||
}
|
}
|
||||||
return size(filteredIterable(iterable, EqualPredicate.<E>equalPredicate(obj)));
|
return size(filteredIterable(emptyIfNull(iterable), EqualPredicate.<E>equalPredicate(obj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -971,7 +990,7 @@ public class IterableUtils {
|
||||||
public static <E> String toString(final Iterable<E> iterable,
|
public static <E> String toString(final Iterable<E> iterable,
|
||||||
final Transformer<? super E, String> transformer) {
|
final Transformer<? super E, String> transformer) {
|
||||||
if (transformer == null) {
|
if (transformer == null) {
|
||||||
throw new NullPointerException("transformer may not be null");
|
throw new NullPointerException("Transformer must not be null.");
|
||||||
}
|
}
|
||||||
return IteratorUtils.toString(emptyIteratorIfNull(iterable), transformer);
|
return IteratorUtils.toString(emptyIteratorIfNull(iterable), transformer);
|
||||||
}
|
}
|
||||||
|
@ -1002,4 +1021,46 @@ public class IterableUtils {
|
||||||
transformer, delimiter, prefix, suffix);
|
transformer, delimiter, prefix, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper methods
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fail-fast check for null arguments.
|
||||||
|
*
|
||||||
|
* @param iterable the iterable to check
|
||||||
|
* @throws NullPointerException if iterable is null
|
||||||
|
*/
|
||||||
|
static void checkNotNull(final Iterable<?> iterable) {
|
||||||
|
if (iterable == null) {
|
||||||
|
throw new NullPointerException("Iterable must not be null.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fail-fast check for null arguments.
|
||||||
|
*
|
||||||
|
* @param iterable the iterable to check
|
||||||
|
* @throws NullPointerException if the argument or any of its contents is null
|
||||||
|
*/
|
||||||
|
static void checkNotNull(final Iterable<?>... iterables) {
|
||||||
|
if (iterables == null) {
|
||||||
|
throw new NullPointerException("Iterables must not be null.");
|
||||||
|
}
|
||||||
|
for (final Iterable<?> iterable : iterables) {
|
||||||
|
checkNotNull(iterable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an empty iterator if the argument is <code>null</code>,
|
||||||
|
* or {@code iterable.iterator()} otherwise.
|
||||||
|
*
|
||||||
|
* @param <E> the element type
|
||||||
|
* @param iterable the iterable, possibly <code>null</code>
|
||||||
|
* @return an empty iterator if the argument is <code>null</code>
|
||||||
|
*/
|
||||||
|
private static <E> Iterator<E> emptyIteratorIfNull(final Iterable<E> iterable) {
|
||||||
|
return iterable != null ? iterable.iterator() : IteratorUtils.<E>emptyIterator();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,15 +105,25 @@ public class FluentIterableTest {
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@Test
|
@Test
|
||||||
public void factoryMethodOf() {
|
public void factoryMethodOf() {
|
||||||
List<Integer> result = FluentIterable.of(1, 2, 3, 4, 5).toList();
|
FluentIterable<Integer> iterable = FluentIterable.of(1, 2, 3, 4, 5);
|
||||||
|
List<Integer> result = iterable.toList();
|
||||||
assertEquals(Arrays.asList(1, 2, 3, 4, 5), result);
|
assertEquals(Arrays.asList(1, 2, 3, 4, 5), result);
|
||||||
|
|
||||||
|
iterable = FluentIterable.of(1);
|
||||||
|
assertEquals(1, iterable.size());
|
||||||
|
assertFalse(iterable.isEmpty());
|
||||||
|
assertEquals(Arrays.asList(1), iterable.toList());
|
||||||
|
|
||||||
result = FluentIterable.of(new Integer[0]).toList();
|
result = FluentIterable.of(new Integer[0]).toList();
|
||||||
assertTrue(result.isEmpty());
|
assertTrue(result.isEmpty());
|
||||||
|
|
||||||
final Iterable<Integer> it = null;
|
final Iterable<Integer> it = null;
|
||||||
result = FluentIterable.of(it).toList();
|
try {
|
||||||
assertTrue(result.isEmpty());
|
FluentIterable.of(it).toList();
|
||||||
|
fail("expecting NullPointerException");
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -151,9 +161,12 @@ public class FluentIterableTest {
|
||||||
Collections.sort(combinedList);
|
Collections.sort(combinedList);
|
||||||
assertEquals(combinedList, result);
|
assertEquals(combinedList, result);
|
||||||
|
|
||||||
result = FluentIterable.of(iterableOdd).collate(null).toList();
|
try {
|
||||||
List<Integer> expected = IterableUtils.toList(iterableOdd);
|
FluentIterable.of(iterableOdd).collate(null).toList();
|
||||||
assertEquals(expected, result);
|
fail("expecting NullPointerException");
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -309,9 +322,12 @@ public class FluentIterableTest {
|
||||||
Collections.sort(combinedList);
|
Collections.sort(combinedList);
|
||||||
assertEquals(combinedList, result);
|
assertEquals(combinedList, result);
|
||||||
|
|
||||||
result = FluentIterable.of(iterableOdd).zip((Iterable<Integer>) null).toList();
|
try {
|
||||||
List<Integer> expected = IterableUtils.toList(iterableOdd);
|
FluentIterable.of(iterableOdd).zip((Iterable<Integer>) null).toList();
|
||||||
assertEquals(expected, result);
|
fail("expecting NullPointerException");
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
result = FluentIterable.of(Arrays.asList(1, 4, 7)).zip(Arrays.asList(2, 5, 8), Arrays.asList(3, 6, 9)).toList();
|
result = FluentIterable.of(Arrays.asList(1, 4, 7)).zip(Arrays.asList(2, 5, 8), Arrays.asList(3, 6, 9)).toList();
|
||||||
combinedList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
combinedList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||||
|
@ -354,7 +370,12 @@ public class FluentIterableTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void size() {
|
public void size() {
|
||||||
assertEquals(0, FluentIterable.of((Iterable<?>) null).size());
|
try {
|
||||||
|
FluentIterable.of((Iterable<?>) null).size();
|
||||||
|
fail("expecting NullPointerException");
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
assertEquals(0, FluentIterable.of(emptyIterable).size());
|
assertEquals(0, FluentIterable.of(emptyIterable).size());
|
||||||
assertEquals(IterableUtils.toList(iterableOdd).size(), FluentIterable.of(iterableOdd).size());
|
assertEquals(IterableUtils.toList(iterableOdd).size(), FluentIterable.of(iterableOdd).size());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue