Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6463989

(coll) Provide Iterable utility methods and light-weight Iterable implementations



    • Enhancement
    • Status: Closed
    • P4
    • Resolution: Won't Fix
    • 5.0
    • None
    • core-libs


      In Java 5, the Iterable class is a compelling option when settling on a type to use for passing lists between methods or classes. Unlike arrays, Iterables can be safely used with parameterized types, and are easily concatenated. Unlike Collections, Iterables are light-weight to implement and make explicit the frequent assumption that the list will not be modified.

      Unfortunately, support in the APIs for arbitrary Iterables is almost nonexistent. The following operations and types (a few of which have been mentioned by others in RFEs) would be quite useful. Except where noted, these operations are meant to be defined lazily -- if Iterable B is defined in terms of Iterable A, then subsequent changes to A are reflected in B.

      - boolean isEmpty(Iterable<?>): Do "iterable.iterator().hasNext()"

      - String toString(Iterable<?>): Make a String following the Collection.toString contract

      - boolean equals(Iterable<?>, Iterable<?>): Equality, as defined by List.equals

      - int hashCode(Iterable<?>): Hash code, as defined by List.hashCode

      - int size(Iterable<?>): Compute the size (possibly O(n))

      - <T> T last(Iterable<? extends T>): Get the last value (possibly O(n))

      - <T> Iterable<T> compose(Iterable<? extends T>, Iterable<? extends T>): Concatenate two iterables

      - <T> Iterable<T> compose(T, Iterable<? extends T>): Place a value at the front of an iterable

      - <T> Iterable<T> compose(Iterable<? extends T>, T): Place a value at the end of an iterable

      - <T> Iterable<T> empty(): Return an empty iterable

      - <T> Iterable<T> filter(Iterable<? extends T>, Predicate<? super T>): Filter out members that don't conform to a predicate (presupposes the existence of a Predicate class)

      - <S, T> Iterable<T> map(Iterable<? extends S>, Function<? super S, ? extends T>): Define a new iterable in terms of some operation applied to another (presupposes the existence of a Function class)

      - <S, T> Iterable<Pair<S, T>> zip(Iterable<? extends S>, Iterable<? extends T>): Produce an iterable of pairs, given two iterables of the same length (presupposes the existence of a Pair class); useful in a for-each loop where two lists need to be traversed simultaneously

      - Iterable<Integer> sequence(int first, int last): Create a sequence from first to last

      - <T> Iterable<T> sequence(T, Function<? super T, ? extends T>): Create an infinite sequence as computed by a function (presupposes the existence of a Function class)

      - <T> Iterable<T> sequence(T, Function<? super T, ? extends T>, int): Create a finite sequence as computed by a function (presupposes the existence of a Function class)

      - <T> Iterable<T> immutable(Iterable<? extends T>): Wrap the given iterable in an immutable wrapper, preventing mutation via casting or Iterator.remove() (mutation can still be observed if the original is mutated)

      - <T> Iterable<T> snapshot(Iterable<? extends T>): Create a copy of the given iterable as it now stands; later mutations will not be reflected in the result

      - <T> Iterable<T> asIterable(Iterator<? extends T>): Create a one-shot iterable based on the given iterator (useful in a for-each loop)

      - <T> Iterable<T> asIterable(T...): Convert an array to an iterable (can also be defined for all primitive array types); by using varargs, we also have a convenient way to define literal iterables, but this approach is limited by the fact that T here must be reifiable to be safe. The workaround is to define a number of makeIterable(T, T, T) methods, each with a different number of arguments, up to a reasonable amount (10, perhaps)

      - Iterable<Character> asIterable(CharSequence): Treat a CharSequence (such as a String) as an Iterable

      - <T> Iterator<T> asIterator(Enumeration<? extends T>): Convert an Enumeration to an *Iterator*. A departure from all the *Iterable* methods, but this would seem like an appropriate place for it.

      - <T> List<T> asList(Iterable<? extends T>): Convert an Iterable to a List (by casting or by creating a new List)

      - <T> Iterable<T> reverse(Iterable<? extends T>): Reverses the given iterable (can't be performed lazily)

      - <T> Iterable<T> shuffle(Iterable<? extends T>, Random): Randomly shuffles the given values (not necessarily performed lazily; this could alternatively be defined on Collections, along with all the Collections.sort() methods)

      - <T> Iterable<T> skipFirst(Iterable<? extends T>): Produce an iterable that doesn't contain the first value

      - <T> Iterable<T> skipLast(Iterable<? extends T>): Produce an iterable that doesn't contain the last value

      - <T> Iterable<T> truncate(Iterable<? extends T>, int): Produce an iterable with the first x elements

      - interface SizedIterable<T> extends Iterable<T> { public int size(); }: Allows slightly more powerful access to the data structure, while remaining lightweight. Collection would implement this interface. All the above could be defined in terms of SizedIterables.

      While the necessity of each specific operation listed above is open to debate, the necessity of *some* form of a java.util.Iterables utility class seems clear. Otherwise, there is no reason to introduce the Iterable class in the first place -- the language could have just performed for-each iteration on Collections instead.

      Iterable, or an interface like it, really should have been around when Collections were first defined with the concept of "unsupported operations." It is possible to do everything that might be done with an Iterable by simply using a deficient form of Collection that supports almost no operations. (AbstractSequentialList provides something like this, but requires the implementation of the more complicated ListIterator rather than just Iterator.) But resorting to such a scheme essentially defeats the purpose of static typing. If a method produces an Iterable, it really shouldn't claim to produce a Collection. And if a method does not need the extra facilities provided by Collection, it ought to be defined in terms of Iterable.

      There are equivalents to many of the proposed operations in the Collection classes. But they are generally not implemented in as lightweight a manner as the Iterable versions could be. For example, iterable composition is a simple object allocation, while composition of two collections is generally O(n) (n being the size of the second collection), because the second collection's values must be integrated into the first's data structures.

      An open-source implementation of these operations, along with others, is used by the DrJava project and can be found here:

      The javadocs are here:


        Issue Links



              smarks Stuart Marks
              ndcosta Nelson Dcosta (Inactive)
              0 Vote for this issue
              3 Start watching this issue