34

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?

Albert
  • 65,406
  • 61
  • 242
  • 386
  • See also http://stackoverflow.com/questions/1527856/how-can-i-iterate-through-the-unicode-codepoints-of-a-java-string – rogerdpack Mar 16 '15 at 20:03

12 Answers12

32

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();
    }
  };
}
ColinD
  • 108,630
  • 30
  • 201
  • 202
  • 3
    Thanks for the hint. So I guess, the answer to my question is "No". – Albert Oct 13 '10 at 15:24
  • @Albert: Yeah, I don't think there's anything in the standard library for doing exactly what you want. Just pointing out that code that does what you want does exist in a solid, well-tested library. – ColinD Oct 13 '10 at 15:28
  • @Albert: You can, of course, loop through the String char-by-char in for example `for` loop by using the `String#toCharArray()` method. – Esko Oct 13 '10 at 16:21
  • 1
    @Esko: That came up in another answer, which I guess was deleted... he needs an `Iterator` specifically. – ColinD Oct 13 '10 at 16:22
  • 2
    @muffin: An `Iterator` is not an `Iterable` (and a `Character` is not a `CharSequence`). – ColinD Aug 29 '14 at 18:42
  • @ColinD Yeah, I just realized my mistake. Here, have my upvote back. (And wow! @ the fast reply) – muffin Aug 29 '14 at 18:44
  • 2
    But please note that iterating through chars may not be what you want if your string has surrogate unicode chars (i.e. characters that require more than a single java Character to be expressed). Example code here: https://gist.github.com/EmmanuelOga/48df70b27ead4d80234b#file-iteratecodepoints-java-L90 – Emmanuel Oga Oct 12 '14 at 09:12
18

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.

aioobe
  • 413,195
  • 112
  • 811
  • 826
14
for (char c : myString.toCharArray()) {

}
neontapir
  • 4,698
  • 3
  • 37
  • 52
user1680517
  • 157
  • 1
  • 3
4

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();
        }
    };
}
Lee
  • 345
  • 2
  • 4
2
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()) 
virgium03
  • 627
  • 1
  • 5
  • 14
2

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();
cyber-monk
  • 5,470
  • 6
  • 33
  • 42
  • `List` and `Set` are **not** implementing `Iterator`. – whiskeysierra Oct 13 '10 at 22:04
  • They are implementing the `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. – Albert Oct 14 '10 at 11:28
  • @Willi, You are correct, the List and Set interfaces are subinterfaces of Collection which contains the .interator() method. If you look closely this is accomplished by extending abstract classes containing private subclasses that indeed implement Iterator, which iterates over the data within the List or Set. I should have stated that both List and Set provide a method for obtaining an Iterator. – cyber-monk Nov 02 '10 at 17:11
  • @Albert, this solution is somewhat inefficient, but one of the main reasons for using an Iterator is because it allows one to: "remove elements from the underlying collection during the iteration with well-defined semantics", which this solution supports. The Iterator returned by Guava ImmutableList is actually an UnmodifiableIterator http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/UnmodifiableIterator.html which throws an exception when remove() is called. This begs the question, why are you using an Iterator if removal is not needed? – cyber-monk Nov 02 '10 at 17:27
  • @cyber-monk: The `Iterator` contract specifically allows that `remove()` is not supported. Also, there is no alternative to `Iterator` which you could use otherwise. – Albert Nov 02 '10 at 17:31
  • @cyber-monk The `iterator()` is specified by `Iterable`, to be precise. – whiskeysierra Nov 02 '10 at 20:50
  • @Willi, Good point, the Collection interface implements Iterable, the private subclasses in AbstractList, AbstractMap, etc. implement Iterator. – cyber-monk Nov 03 '10 at 16:00
1

This can be done with a little help from Apache Commons Lang (if you don't want to use Guava, and want a true java.util.Iterator.

private static Iterator<Character> iterator(String string) {
    return Arrays.asList(ArrayUtils.toObject(string.toCharArray())).iterator();
}
wool.in.silver
  • 547
  • 1
  • 3
  • 13
1

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.

Aison
  • 61
  • 3
  • 1
    You mention codePoints(). One important aspect of codePoints() is that it allows you to deal with surrogate chars. See [this answer](http://stackoverflow.com/a/40444598/99717). – Hawkeye Parker Nov 06 '16 at 00:03
1

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;
    }
leonbloy
  • 73,180
  • 20
  • 142
  • 190
0

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

Qwerky
  • 18,217
  • 6
  • 44
  • 80
  • But isn't this terribly inefficient? – Albert Oct 13 '10 at 15:15
  • Yeah, this would just create a single element `Iterator`. – ColinD Oct 13 '10 at 15:20
  • You both are right. I have checked it and cryed in shame. Deleting the comment. My excuses. it's not my best day, for true. – Tomas Narros Oct 13 '10 at 15:36
  • 1
    I don't believe it worked that way in 1.4 either... I think it was a compiler error to pass a primitive array to `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. – ColinD Oct 13 '10 at 15:41
0

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.

0

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.

overthink
  • 23,985
  • 4
  • 69
  • 69