views:

231

answers:

7

Hi,

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?

A: 
Qwerky
But isn't this terribly inefficient?
Albert
Yeah, this would just create a single element `Iterator<char[]>`.
ColinD
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
@Qwerky: 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
+8  A: 

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
Thanks for the hint. So I guess, the answer to my question is "No".
Albert
@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
@Albert: You can, of course, loop through the String char-by-char in for example `for` loop by using the `String#toCharArray()` method.
Esko
@Esko: That came up in another answer, which I guess was deleted... he needs an `Iterator<Character>` specifically.
ColinD
+3  A: 
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
That is not an `Iterator<Character>` and I really only want such thing here.
Albert
how about this: http://www.java2s.com/Code/JavaAPI/java.util/implementsIteratorCharacter.htm
virgium03
@virgium03: Implementing both `Iterable` and `Iterator` is a really bad idea and should never be done.
ColinD
@virgium03: Mostly like that. But is this in the standard lib?
Albert
well, i don't know if it is implemented in the standard lib but you can create your own class like in the example
virgium03
@virgium03 The code in your example is extremely broken. Returning `this` in the `iterator()` method is totally wrong and breaks the contract.
Willi
A: 

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.

Vash
It's incorrect to say that an `Iterator` only iterates over a collection. `Iterator` is a simple interface that can iterate over whatever it's implemented to iterate over.
ColinD
+1 You have right that only lost me.
Vash
+3  A: 

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
A: 

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
`List` and `Set` are **not** implementing `Iterator`.
Willi
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
A: 

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