195

with Java5 we can write:

Foo[] foos = ...
for (Foo foo : foos) 

or just using an Iterable in the for loop. This is very handy.

However you can't write a generic method for iterable like this:

public void bar(Iterable<Foo> foos) { .. }

and calling it with an array since it is not an Iterable:

Foo[] foos = { .. };
bar(foos);  // compile time error 

I'm wondering about the reasons behind this design decision.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
dfa
  • 114,442
  • 31
  • 189
  • 228
  • 1
    I'm kind of surprised that Google Collections doesn't have an array iterable class yet. – Michael Myers Jul 21 '09 at 15:58
  • 8
    Arrays.asList is good enough I suppose – dfa Jul 21 '09 at 16:00
  • I forgot about that. So why don't you use asList then? – Michael Myers Jul 21 '09 at 16:12
  • Or is this just a philosophical question? – Michael Myers Jul 21 '09 at 16:13
  • 17
    it is a philosophical question – dfa Jul 21 '09 at 17:09
  • See also: http://stackoverflow.com/questions/362367/java-arrays-generics-java-equivalent-to-c-ienumerablet/366689#366689 – finnw Nov 05 '09 at 21:16
  • 2
    a good reason to deal with arrays in Java 5+ is varargs methods. – Jeff Walker Aug 05 '10 at 16:29
  • @MichaelMyers Would asList() not cause a non-trivial performance drop? Both while converting to/from and for get/setting – Aaron J Lang Jan 03 '12 at 02:32
  • 1
    @AaronJLang: Not really; the list returned by asList() uses the parameter array as backing, so the array doesn't have to be copied. – Michael Myers Jan 03 '12 at 23:44
  • @MichaelMyers asList returns an immutable List, which is unhandy if you want to perform changes on the List. – Torsten Apr 04 '12 at 07:39
  • 2
    @Torsten: true, but if you're passing it to a method that accepts an Iterable, you're likely not making any changes anyway. – Michael Myers Apr 04 '12 at 13:33
  • @MichaelMyers I just came across a method (of some framework) that accepted an Iterable and turned it into a List, but simply returned the Iterable if it was a List already. What I was looking for, was a method that accepted an array turning it to a mutable List. So turning the array to an immutable List with asList wouldn't get me any further, but that's probably a design fault of the method I found. – Torsten Apr 05 '12 at 06:44
  • 5
    Actually, Arrays.asList is *not* good enough because it doesn't work on arrays of primitive types. The only built-in way to generically iterate (boxed) elements of primitive types is with reflection, using `java.lang.reflect.Array`, but its performance is weak. However, you can write your own iterators (or List implementations!) to wrap arrays of primitive types if you want. – Boann Jan 08 '13 at 13:07
  • I was looking for this question online. Actually I think it of this way. If the array lends itself to an indexed way of accessing its elements what is the need of an extra iterator? Its waste of work. Simple way of iterating is : for ( int i = 0; i < a.length; i++) a[i]. that's it. and the best part is you can access any element in O(1) – SomeDude Jun 14 '13 at 16:08

5 Answers5

80

Arrays can implement interfaces (Cloneable and java.io.Serializable). So why not Iterable? I guess Iterable forces adding an iterator method, and arrays don't implement methods. char[] doesn't even override toString. Anyway, arrays of references should be considered less than ideal - use Lists. As dfa comments, Arrays.asList will do the conversion for you, explicitly.

(Having said that, you can call clone on arrays.)

Gray
  • 115,027
  • 24
  • 293
  • 354
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 24
    > "... and arrays don't implement methods." I think this is another philosophical question; arrays weren't ever primitive types, and the Java philosophy reads that "Everything is an object (except primitive types)". Why, then, do arrays not implement methods even though there are a gazillion operations that one would want to use an array for from the start. Oh, that's right, arrays were the only strongly typed collections before generics came along as a sorry hindsight. – fatuhoku Nov 28 '11 at 12:02
  • 2
    If you've got data in an array, it's possible that you're doing low-level, performance critical work such as dealing with byte[]'s read from streams. The inability to iterate arrays probably stems from Java generics not supporting primitives as type arguments, as @Gareth says below. – Drew Noakes Dec 26 '12 at 00:32
  • 2
    @FatuHoku Suggesting generics were a sorry hindsight is incorrect. The desirability of generics was always appreciated. Arrays aren't primitives (I didn't say they were), but they are low-level. The one thing you want to do with arrays is use them as an implementation detail for vector-like structures. – Tom Hawtin - tackline Jan 08 '13 at 14:07
  • 2
    `Iterator` also requires `remove(T)`, though it is allowed to throw an `UnsupportedOperationException`. – wchargin Mar 19 '14 at 22:39
  • 1
    Arrays do implement methods: they implement all the methods of `java.lang.Object`. – mhsmith Aug 02 '17 at 12:34
  • @mhsmith The methods of `Object` are implemented by `Object` for arrays. – Tom Hawtin - tackline Aug 13 '17 at 10:23
  • Ah, you're right, they just inherit the default implementations of `toString`, `equals` and `hashCode`, which are fairly useless for arrays. – mhsmith Aug 16 '17 at 23:29
62

The array is an Object, but its items might not be. The array might hold a primitive type like int, which Iterable can't cope with. At least that's what I reckon.

Gareth Adamson
  • 637
  • 5
  • 2
  • 3
    This means in order to support the `Iterable` interface, primitive arrays must be specialized to use the wrapper classes. None of this is really a big deal though, since type parameters are all fake anyway. – thejoshwolfe Aug 23 '11 at 22:21
  • 9
    This would not prevent Object arrays from implementing Iterable. It would also not prevent primitive arrays from implementing Iterable for the wrapped type. – Boann Jan 08 '13 at 12:58
  • 2
    Autoboxing could handle this – Tim Büthe Apr 05 '13 at 09:13
  • I think this is the correct reason. It will not work satisfactory for arrays of primitive types, until Generics support primitive types (e.g. `List` instead of `List`, etc). A hack could be done with wrappers but at a performance loss - and more importantly - if this hack was done, it'ld prevent implementing it properly in Java in the future (for example `int[].iterator()` would forever be locked to return `Iterator` rather than `Iterator`). Perhaps, the upcoming value-types + generic-specialization for Java (project valhalla) will make arrays implement `Iterable`. – DisplayName May 04 '18 at 15:59
20

Arrays ought to support Iterable, they just don't, for the same reason that .NET arrays don't support an interface that allows readonly random access by position (there is no such interface defined as standard). Basically, frameworks often have annoying little gaps in them, which it's not worth anyone's time to fix. It wouldn't matter if we could fix them ourselves in some optimal way, but often we can't.

UPDATE: To be even-handed, I mentioned .NET arrays not supporting an interface that supports random access by position (see also my comment). But in .NET 4.5 that exact interface has been defined and is supported by arrays and the List<T> class:

IReadOnlyList<int> a = new[] {1, 2, 3, 4};
IReadOnlyList<int> b = new List<int> { 1, 2, 3, 4 };

All is still not quite perfect because the mutable list interface IList<T> doesn't inherit IReadOnlyList<T>:

IList<int> c = new List<int> { 1, 2, 3, 4 };
IReadOnlyList<int> d = c; // error

Maybe there is a possible backward compatibility gotcha with such a change.

If there's any progress on similar things in newer versions of Java, I'd be interested to know in the comments! :)

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • 9
    .NET arrays implement the IList interface – Tom Gillen Nov 25 '11 at 15:08
  • 2
    @Aphid - I said *readonly* random access. `IList` exposes operations for modifying. It would be great if `IList` had inherited something like a `IReadonlyList` interface, which would have just had `Count` and `T this[int]` and inherited `IEnumerable` (which already supports readonly enumeration). Another great thing would be an interface for obtaining a reverse-order enumerator, which the `Reverse` extension method could query for (just as the `Count` extension method queries for `ICollection` to optimise itself.) – Daniel Earwicker Nov 25 '11 at 22:38
  • Yes, it would much be better if things had been designed that way. The IList interface does define IsReadOnly and IsFixedSize properties, which are implemented appropriately by array. That has always struck me as a very bad way of doing it though, as it offers no compile time checking that the list you are given is in fact readonly, and I very rarely see code which checks these properties. – Tom Gillen Feb 24 '12 at 12:03
  • 2
    Arrays in .NET implement `IList` & `ICollection` since .NET 1.1, and `IList` and `ICollection` since .NET 2.0. This is yet another case where Java is far behind the competition. – Amir Abiri Aug 23 '14 at 17:24
  • @TomGillen: My biggest problem with `IList` is that it doesn't provide more queryable attributes. I'd say a proper set should include IsUpdateable, IsResizable, IsReadOnly, IsFixedSize, and ExistingElementsAreImmutable for starters. The question of whether code a reference can, without typecasting, modify a list is separate from the questions of whether code which holds a reference to a list which it isn't supposed to modify can safely share that reference directly with outside code, or whether it can safely assume some aspect of the list will never change. – supercat Dec 17 '14 at 21:48
  • @TomGillen: I really don't think there's room in the type system to have different `IWhateverKindOfLIst` interfaces for every combination of attributes. Further, trying to incorporate such details into the type system would complicate the design of wrapper classes. – supercat Dec 17 '14 at 21:52
15

Unfortunately, arrays aren't 'class-enough'. They don't implement the Iterable interface.

While arrays are now objects that implement Clonable and Serializable, I believe an array isn't an object in the normal sense, and doesn't implement the interface.

The reason you can use them in for-each loops is because Sun added in some syntatic sugar for arrays (it's a special case).

Since arrays started out as 'almost objects' with Java 1, it would be far too drastic of a change to make them real objects in Java.

dlamblin
  • 43,965
  • 20
  • 101
  • 140
jjnguy
  • 136,852
  • 53
  • 295
  • 323
  • 1
    well, I'm wondering exactly why they don't implement the Iterable interface! – dfa Jul 21 '09 at 15:56
  • 1
    Since an array isn't an object in the normal sense, it can't implement the interface. – jjnguy Jul 21 '09 at 15:57
  • @dfa I'm afraid only Sun could really answer that – matt b Jul 21 '09 at 15:58
  • they dont implement the iterable interface because they are not standard classes and cannot implement an interface – Spencer Stejskal Jul 21 '09 at 15:58
  • 14
    Still, there's sugar for the for-each loop, so why can't there be sugar for Iterable? – Michael Myers Jul 21 '09 at 16:00
  • You would think that they could make an array act more like an iterable. – jjnguy Jul 21 '09 at 16:09
  • 9
    @mmyers: The sugar used in for-each is *compile-time* sugar. That's a lot easier to do than *VM* sugar. Having said which, .NET arrays are significantly better in this area... – Jon Skeet Jul 21 '09 at 16:14
  • 13
    Arrays *can* implement interfaces. They implement `Cloneable` and `Serializable` interfaces. – notnoop Jul 21 '09 at 16:42
  • really ? – jjnguy Jul 21 '09 at 16:43
  • 37
    java arrays are objects in all senses. Please remove that bit of misinformation. They just don't implement Iterable. – ykaganovich Jul 21 '09 at 17:04
  • matt b: Most of the people who works on the 1.5 languages features no longer work for Sun. – Tom Hawtin - tackline Jul 21 '09 at 23:20
  • 6
    An array is an Object. It support *useful* :P methods like wait(), wait(n), wait(n,m), notify(), notifyAll(), finalize(), a pointless implementation of toString() The only useful method is getClass(). – Peter Lawrey Feb 04 '10 at 22:32
  • 2
    They could do the Iterable sugar compile-time too. If you passed an array to something which wanted Iterable, it *could* put the Arrays.asList() around it for you... – Hakanai Jan 04 '13 at 00:10
  • 3
    They could easily wrap arrays in standard library into something with methods, preserving old `Object[]` syntax for back compat. And things would have become more convenient. Everytime I encounter myself to work with java I feel like my hands tied. I'm happy scala has this in stdlib, and also finally collections have `join`... – dmitry Mar 14 '13 at 15:10
  • Arrays _should be_ iterable, but in classic Java fashion ... "implement feature 70% and call it done" ... and leave the developers to have to work around silly things such as this. – Josh M. Mar 03 '21 at 17:21
5

The compiler actually translates the for each on an array into a simple for loop with a counter variable.

Compiling the following

public void doArrayForEach() {
    int[] ints = new int[5];

    for(int i : ints) {
        System.out.println(i);
    }
}

and then decompiling the .class file yields

public void doArrayForEach() {
    int[] ints = new int[5];
    int[] var2 = ints;
    int var3 = ints.length;

    for(int var4 = 0; var4 < var3; ++var4) {
        int i = var2[var4];
        System.out.println(i);
    }
}
das Keks
  • 3,723
  • 5
  • 35
  • 57