views:

296

answers:

7

Many Java framework classes implement Iterable, however String does not. It makes sense to iterate over characters in a String, just as one can iterate over items in a regular array.

Is there a reason why String does not implement Iterable?

+8  A: 

An iterator in Java specifically applies to a collection of discrete items (objects). A String is not really a "collection" of discrete characters. It is a single entity that happens to consist of characters. Therefore, it does not make sense (in some cases, or most) in the context of Collections (which is what iterators are for) to treat each individual character as a discrete entity. It makes sense (in some cases or most) to treat the String as a whole. That being said, you can treat a String as a collection or characters and access each character like this:

for (int i = 0; i < str.length(); i++) {
  System.out.println(str.charAt(i));
}

Or as others have said:

for(char c : str.toCharArray()) {
  System.out.println(c);
}

Also note that you cannot modify a character of a String in place because Strings are immutable. The mutable companion to a String is StringBuilder (or the older StringBuffer).

EDIT

To clarify based on the comments on this answer. I'm trying to explain why there is no Iterator on a String. I'm not trying to say that it's not possible. The question is if it makes sense to have an iterator on just a String. String provides CharSequence, which, if conceptually, is different from a String. A String is usually thought of as a single entity, whereas CharSequence is exactly that: a sequence of characters. It would make sense to have an iterator on a sequence of characters (i.e., on CharSequence), but not simply on a String itself.

As Foxfire has rightly pointed out in the comments, String implements the CharSequence interface, so type-wise, a String is a CharSequence. Semantically, it seems to me that they are two separate things - I'm probably being pedantic here, but when I think of a String I usually think of it as a single entity that happens to consist of characters. Consider the difference between the sequence of digits 1, 2, 3, 4 and the number 1234. Now consider the difference between the string abcd and the sequence of characters a, b, c, d. I'm trying to point out this difference.

In my opinion, asking why String doesn't have an iterator is like asking why Integer doesn't have an iterator so that you can iterate over the individual digits.

I might be splitting hairs, but I was only trying to help ;).

Vivin Paliath
Surely treating a string as a collection of letters isn't entirely without precedent, and to argue it on a "makes sense" case seems a little spurious.
Svend
@Svend that's true - I was actually at a loss for words - I think I wanted to say "it doesn't make sense in some cases" or even "it doesn't make sense in most cases" considering what iterators really are. I will edit my answer.
Vivin Paliath
"A String is not really a "collection" of discrete characters.". Well it is. In fact it even implements CharSequence, which is exactly that: An orderd collection of discrete characters!
Foxfire
@Vivin: there is no specific implication that `Iterator` must act on a collection. Infinite iterators seem to be acceptable in the right context.
polygenelubricants
@Foxfire, agreed - but a `String` by itself is not a `CharSequence`. A `CharSequence` is a sequence of characters that is created from a String. It would make sense to have an iterator on a `CharSequence` but not on just the `String` itself.
Vivin Paliath
@polygenelubricants I am not saying that you _can't_ have an Iterator on a string. I'm only trying to explain why. You can have an iterator on anything you want. The question is if it makes sense.
Vivin Paliath
You can do `foreach (char c in s)` in C#, just beautiful!
FredOverflow
@Vivin: CharSequence is an INTERFACE (exactly as Iterable). So it is the String itself implementing the interface. It is not created from the String.
Foxfire
@Foxfire, point noted. I realize I may be pedantic here, but to me a `String` and a `CharSequence` are two separate things.
Vivin Paliath
@Vivin: Then imho you should just try to answer the original question as: "Why does CharSequence not implement Iterable". (Which of course technically still means "Why does String not implement Iterable")
Foxfire
@Foxfire, indeed. It would make sense to have it on `CharSequence` imho (I've alluded to that in my answer). If the `CharSequence` interface specified an iterator, I think it would make more sense rather than `String` having it. Thanks for the fruitful discussion :)
Vivin Paliath
+3  A: 

If you are really instrested in iterating here:

String str = "StackOverflow";

for (char c: str.toCharArray()){
     //here you go
}
medopal
-1 Sorry, but I don't see what this answer has to do with the question asked.
jarnbjo
A problem might be that toCharArray creates a new array. So this is VERY inefficient.
Foxfire
@Helper: String is immutable. However the returned Array is not. And changinig the Array must not affect the String. So it DOES make a complete copy.
Foxfire
+1 - For small strings, creating a char[] is roughtly as expensive as creating an Iterator - it's an object allocation (and a small amount of memory initialization and copy). As the strings become longer then the memory initialize/copy overhead becomes significant, but still nowhere near as significant as boxing each character.
mdma
+4  A: 

The reason is simple: The string class is much older than Iterable.

And obviously nobody ever wanted to add the interface to String (which is somewhat strange because it does implement CharSequence which is based on exactly the same idea).

However it would be somewhat imperformant because Iterable returns an object. So it would have to Wrap every Char returned.

Edit: Just as comparison: .Net does support enumerating on String, however in .Net Iterable also works on native types so there is no wrapping required as it would be required in Java.

Foxfire
"adding Iterable to String class makes it imperformant", makes sense; but nobody added Itreable to String class just because it was old, seems a bit odd. can you please explain some more?
phoenix24
String existed long before Iterable. So you would have to add the interface later. While that is possible it may - in some corner cases - be a breaking change. And taking into consideration how often String is used this *might* have been something considered risky. This is just guessing. I have no knowledge if these considerations were really affecting that decision. But it seems most likely.
Foxfire
@Foxfire I can't see adding `Iterable` (or any type) to `String` as being a breaking change. It's not like you can subclass `String` (thank god).
Tom Hawtin - tackline
@Tom: Surely in 99.9% of the cases it won't be. But it is easy enough to construct cases (e.g. reflecting on the interfaces) where it could break. Taking into account that basically EVERY application uses String somewhere that still might be a reason.
Foxfire
@Foxfire Any code like that which gets broken, deserves to be broken. I think I am safe in saying it is not a reason brought into consideration.
Tom Hawtin - tackline
A: 

Iterable of what? Iterable<Integer> would make most sense, where each element represents a Unicode codepoint. Even Iterable<Character> would be slow and pointless when we have toCharArray.

Tom Hawtin - tackline
+3  A: 

For what it's worth, my coworker Josh Bloch strongly wishes to add this feature to Java 7:

for (char c : aString) { ... }

and

for (int codePoint : aString) { ... }

This would be the easiest way to loop over chars and over logical characters (code points) ever. It wouldn't require making String implement Iterable, which would force boxing to happen.

Without that language feature, there's not going to be a really good answer to this problem. And he seems very optimistic that he can get this to happen, but I'm not sure.

Kevin Bourrillion
You work with Joshua Bloch? Sweet!
Vivin Paliath
A: 

They simply forgot to do so.

Adrian
A: 

One of the main reasons for making String implement Iterable is to enable the simple for(each) loop, as mentioned above. So, a reason for not making String implement Iterable could be the inherent inefficiency of a naïve implementation, since it requires boxing the result. However, if the implementation of the resulting Iterator (as returned by String.iterator()) is final, the compiler could special-case it and generate byte-code free from boxing/unboxing.

Hallvard Trætteberg