I need a Iterator<Character> from a String object. Is there any available function in Java that provides me this or do I have to code my own?
12 Answers
One option is to use Guava:
ImmutableList<Character> chars = Lists.charactersOf(someString); UnmodifiableListIterator<Character> iter = chars.listIterator(); This produces an immutable list of characters that is backed by the given string (no copying involved).
If you end up doing this yourself, though, I would recommend not exposing the implementation class for the Iterator as a number of other examples do. I'd recommend instead making your own utility class and exposing a static factory method:
public static Iterator<Character> stringIterator(final String string) { // Ensure the error is found as soon as possible. if (string == null) throw new NullPointerException(); return new Iterator<Character>() { private int index = 0; public boolean hasNext() { return index < string.length(); } public Character next() { /* * Throw NoSuchElementException as defined by the Iterator contract, * not IndexOutOfBoundsException. */ if (!hasNext()) throw new NoSuchElementException(); return string.charAt(index++); } public void remove() { throw new UnsupportedOperationException(); } }; } 7 Comments
Iterator<Character> specifically.Iterator is not an Iterable (and a Character is not a CharSequence).It doesn't exist, but it's trivial to implement:
class CharacterIterator implements Iterator<Character> { private final String str; private int pos = 0; public CharacterIterator(String str) { this.str = str; } public boolean hasNext() { return pos < str.length(); } public Character next() { return str.charAt(pos++); } public void remove() { throw new UnsupportedOperationException(); } } The implementation is probably as efficient as it gets.
Comments
for (char c : myString.toCharArray()) { } 2 Comments
char[] is not assignable to Iterable<Character>.Stealing from somebody else in another answer, this is probably the best direct implementation (if you're not going to use guava).
/** * @param string * @return list of characters in the string */ public static List<Character> characters(final String string) { return new AbstractList<Character>() { @Override public Character get(int index) { return string.charAt(index); } @Override public int size() { return string.length(); } }; } Comments
CharacterIterator it = new StringCharacterIterator("abcd"); // Iterate over the characters in the forward direction for (char ch=it.first(); ch != CharacterIterator.DONE; ch=it.next()) // Iterate over the characters in the backward direction for (char ch=it.last(); ch != CharacterIterator.DONE; ch=it.previous()) 6 Comments
Iterator<Character> and I really only want such thing here.Iterable and Iterator is a really bad idea and should never be done.this in the iterator() method is totally wrong and breaks the contract.Short answer: No, you have to code it.
Long answer: List and Set both have a method for obtaining an Iterator (there are a few other collection classes, but probably not what your looking for). The List and Set interfaces are a part of the Collections Framework which only allow for adding/removing/iterating Objects like Character or Integer (not primitives like char or int). There is a feature in Java 1.5 called auto-boxing that will hide this primitive to Object conversion but I don't recommend it and it won't provide what you want in this case.
An alternative would be to wrap the String in a class of your own that
implements Iterator<Character> but that might be more work than it is worth.
Here is a code snippet for doing what you want:
String s = ""; List<Character> list = new ArrayList<Character>(s.length()); for (int i = 0; i < s.length(); i++) { // note that Character.valueOf() is preferred to new Character() // you can omit the Character.valueOf() method // and Java 1.5+ will auto-box the primitive into an Object list.add(Character.valueOf(s.charAt(i))); } Iterator<Character> iterator = list.iterator(); 7 Comments
List and Set are not implementing Iterator.Iterable interface (which provides a iterator() function which returns an Iterator) so that is ok. But your code is inefficient because it creates a full copy of the string.Iterator contract specifically allows that remove() is not supported. Also, there is no alternative to Iterator which you could use otherwise.No direct way. Not difficult to code, though:
public static Iterator<Character> gimmeIterator(final String x) { Iterator<Character> it = new Iterator<Character>() { String str = x == null ? "" : x; int pos = -1; // last read public boolean hasNext() { return(pos+1 < str.length()); } public Character next() { pos++; return str.charAt(pos); } public void remove() { throw new UnsupportedOperationException("remove unsupported for this iterator"); } }; return it; } Comments
With java 8 or newer you can use the stream facility. With the chars() method you can access an IntStream. The IntStream supports the method iterator() that returns an OfInt iterator. OfInt implements Iterator<Integer>.
String str = "foobar"; OfInt ofit = str.chars().iterator(); Iterator<Integer> it = ofit; It is not a perfect answer, since you asked for Iterator<Character>.
Btw: With str.codePoints() you can also access a code point IntStream.
1 Comment
Not sure if there is a more direct way but you could do something like;
Arrays.asList(string.toCharArray()).iterator(); Scratch that; Arrays.asList doesn't do what I seem to remember it doing.
Edit 2: Seems like it last worked this way in 1.4
4 Comments
Iterator<char[]>.Arrays.asList(Object[]) in 1.4. When the method was (mistakenly) changed to a varargs method in 1.5 it became legal to pass a primitive array to it, but it doesn't do what you expect.The Iterator iterate over a collection or whatever implements it. String class does nost implement this interface. So there is no direct way.
To iterate over a string you will have to first create a char array from it and then from this char array a Collection.
1 Comment
Iterator only iterates over a collection. Iterator is a simple interface that can iterate over whatever it's implemented to iterate over.This feels dirty, but you could use Scanner with empty string delimiter:
Scanner scanner = new java.util.Scanner(myInput).useDelimiter(""); Scanner implements Iterator, so scanner is now an Iterator of length-1 strings, which is close.
To continue with the (very?) dirty, in Java 8 you can then do this to succinctly iterate by chars:
for (String s: (Iterable<String>)() -> scanner) { char c = s.charAt(0); System.out.println(c); } For details on why () -> scanner works (and why it may be dangerous, though not in this use case), see Explain how this lambda can be assigned to an Iterable.