45

I wonder why the Collection.addAll() method only accepts other Collections but not Iterables. Why is that?

Any similar method to do that for Iterables?

Albert
  • 65,406
  • 61
  • 242
  • 386
  • if you are looking for the easiest way to add an iterator to a collection without an explicit loop, you could use `yourCollection.addAll(org.apache.commons.collections.IteratorUtils.toList(yourIterable.iterator()))` – mihi Sep 30 '10 at 15:30
  • 1
    and in case your Iterable is an array, use `java.util.Arrays.asList()` – mihi Sep 30 '10 at 15:32
  • 1
    Arrays do not implement `Iterable` – Steve Kuo Sep 30 '10 at 21:16
  • @SteveKuo: Can you elaborate the meaning of that with respect to the question? – O. R. Mapper Jun 04 '14 at 13:42

5 Answers5

39

Presumably because the Collection interface was introduced in Java 1.2 whereas Iterable appeared only in 1.5, and changing the interface would break all existing implementations.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • 3
    This doesn't explain why the method wasn't subsequently added. – user48956 Dec 16 '14 at 15:41
  • @user48956: yes, it does: "changing the interface would break all existing implementations". Though that actually became untrue with the introduction of default methods in Java 8. – Michael Borgwardt Dec 16 '14 at 20:55
  • @user48956: not sure why you think that is relevant. It's not. – Michael Borgwardt Dec 17 '14 at 00:41
  • Because it was possible to add addAll(Iterable) into addition to addAll(Collection) when Iterable was added. Was there some reason it wasn't added? – user48956 Dec 17 '14 at 03:34
  • @user48956: To repeat myself a third time: "changing the interface [by adding a method to it] would break all existing implementations [because they would now be missing that method]". That's the kind of braking change that will NEVER happen in the Java Standard API. – Michael Borgwardt Dec 17 '14 at 09:34
  • I'm very confused. How does adding an additional method cause a method to be missing? – user48956 Dec 17 '14 at 21:16
  • @user48956: I'm not sure how much more clearly I can spell it out: There are classes whose code says "implements Collection". If you add a method to the Collection interface, then those classes are now missing that method and will not compile (or, if already compiled, fail validation during class loading) when used with the new version of Java where Collection has that method. And this loss of downward compatibility (where old code won't run on a new version of Java) is something that Java jas traditionally avoided at all costs. – Michael Borgwardt Dec 18 '14 at 08:31
  • They could've added a `Collections.addAll(coll, it)` for `Iterable` and `Iterator` in Java 5 though, with a `@see` on `Collection#addAll`. Granted, it can't be clever about downcasting the argument, but I'm pretty sure most of the workarounds aren't doing that either. – TWiStErRob Aug 03 '16 at 12:09
  • 2
    This doesn't explain why it wasn't added as a default method in Java 8. I'm leaning towards [@OscarRyz's answer](http://stackoverflow.com/a/3832084/1553851) that it has to do with `Collection` representing a finite set of elements. – shmosel Sep 02 '16 at 23:59
34

When in doubt, always check Guava (or Commons):

Pixel Elephant
  • 20,649
  • 9
  • 66
  • 83
Michael Brewer-Davis
  • 14,018
  • 5
  • 37
  • 49
  • 5
    +1 for *When in doubt, always check Guava*. Most apache commons libs are great, but commons / collections is annoying because it doesn't support generics. – Sean Patrick Floyd Sep 30 '10 at 15:48
  • It has a fork which supports generics: https://github.com/megamattron/collections-generic – thSoft Apr 06 '12 at 09:23
  • Broken link. Now http://commons.apache.org/proper/commons-collections/javadocs/api-release/index.html – Ian Apr 29 '18 at 02:49
13

Others have answered the "why" extensively.

Any similar method to do that for Iterables?

In Java 8 you don't need addAll any more:

Collection<X> coll = ...;
Iterable<X> it = ...;
it.forEach(coll::add); // coll.addAll(it);
TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
  • This is exactly what I was looking for. Knew it was possible with just the JDK. Thanks! – Michael Jul 07 '17 at 13:41
  • Does that work if the stream if a parallel stream? You would then call `coll.add` concurrently. – Jens Nov 18 '19 at 17:33
  • Anyone has done some benchmarking on this? Is it comparably fast? – kap Dec 14 '20 at 22:40
  • This is not a good solution, since it makes the iterable responsible for the iteration. You give away control in how iteration is done. With an addAll method you simply request the source to provide an iterator. With the **overridable** forEach method you are not in control how the iteration is done. Therefore you can't make any estimates related to performance. – RedCrafter LP Jul 05 '22 at 12:12
11

Basically because an Iterable may never end (that is, hasNext() return true forever).

Also, to keep congruency, you may think a Collection may add all the elements of another collection, but, an Iterable is not necesarily a collection (it may be anything, like the a ResultSet wrapper for instance).

aioobe
  • 413,195
  • 112
  • 811
  • 826
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • Ah, your first point is a good one. I don't really understand what you mean by the second one and how it would affect the `addAll` method. – Albert Sep 30 '10 at 15:32
  • As for the second, an iterable is an interface, pretty much, anything, could implement it, and you may end up in the first situation, with an possible infinite loop. – OscarRyz Sep 30 '10 at 15:40
  • 6
    Not sure I agree. A Collection can be infinite in the same way as an Iterable, as you can construct a valid Collection as a wrapper around an Iterable. – GaryF Sep 30 '10 at 15:43
  • 4
    Nevermind, I've checked the doc, http://download.oracle.com/javase/6/docs/api/java/util/Collection.html#size%28%29 it should return Integer.MAX_VALUE – OscarRyz Sep 30 '10 at 15:54
  • @GaryF I don't think collections are supposed to be infinite collections, or `removeAll()` and `retainAll()` could execute indefinitely. @OscarRyz just because size may be greater than `Integer.MAX_VALUE` doesn't mean it can be infinite. And the interface doesn't even properly support collections larger than `Integer.MAX_VALUE`, since `toArray()` promises to return all the elements even though arrays can't be larger than `Integer.MAX_VALUE`. – shmosel Sep 02 '16 at 23:55
3

There are quite a few things in the core JDK which don't work as well with plain Iterables as they might. I'd recommend using Guava to overcome a lot of these shortcomings.

TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194