let\'s say I have this simple MyArray class, with two simple methods: add, delete and an iterator. In the main method we can see how it is supposed to be used:
My suggestion is to let MyArray
implement the interface java.lang.Iterable
and create an instance of an iterator per iterator()
call (as an anonymous class). Then you can use an instance of MyArray
directly in a foreach
construct:
public class MyArray implements Iterable {
// ...
// Only arr is needed now as an instance variable.
// int start;
// int end;
int[] arr;
// myIterator it;
/**
* From interface Iterable.
*/
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
// The next array position to return
int pos = 0;
public boolean hasNext() {
return pos < arr.length;
}
public Integer next() {
if(hasNext())
return arr[pos++];
else
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
}
Update: According to BertF's comment I updated my code to make it clear, that the only instance variable for class MyArray
is now arr
. The state for the iterator is now inside the anonymous Iterator
implementation. So you can create multiple iterator instances which don't interfere each other.
Iterator is an interface . Iterator<E>
which means only Object can go here (E) .
Iterator<Integer>
is legal but Integer<int>
is not because int is primitive data type
You can change the array to the ArrayList and then iterate over this arraylist. I added getIterator()
method that returns the arraylist.iterator()
and test it in main()
method
import java.util.ArrayList;
import java.util.Iterator;
public class MyArray {
int start;
int end;
ArrayList<Integer> arr;
public MyArray() {
this.start = 0;
this.end = 0;
arr = new ArrayList<Integer>(500);
}
public void add(int el) {
arr.add(el);
this.end++;
}
public void delete() {
arr.remove(arr.size()-1);
this.start++;
}
public Iterator<Integer> getIterator(){
return arr.iterator();
}
public static void main(String[] args) {
MyArray m = new MyArray();
m.add(3);
m.add(299);
m.add(19);
m.add(27);
Iterator<Integer> it = m.getIterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
In my opinion it is better to implement MyArray as common Iterable object, so it can be used in a for statement.
My suggestion:
/**
* My array
*/
public class MyArray<TItem> implements Iterable<TItem>
{
/**
* Internal used iterator.
*/
private class MyArrayIterator<TItem> implements Iterator<TItem>
{
private MyArray<TItem> _array;
/**
* @param array The underlying array.
*/
public MyArrayIterator(MyArray<TItem> array)
{
this._array = array;
}
/**
* Gets the underlying array.
*
* @return The underlying array.
*/
public MyArray<TItem> getArray() {
return this._array;
}
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
return false;
}
@Override
public TItem next() {
// TODO Auto-generated method stub
return null;
}
@Override
public void remove() {
// TODO Auto-generated method stub
}
}
public void add(int el){
// do add
}
public void delete(){
// do delete
}
@Override
public Iterator<TItem> iterator() {
// TODO Auto-generated method stub
return new MyArrayIterator<TItem>(this);
}
}
As I said you can use it in a for statement:
private static void test(MyArray<String> strArray)
{
for (String str: strArray) {
// do something
}
}
EDIT: this does not work for arrays of primitive types: you could use Arrays for this:
it = new Arrays.asList(arr).subList(start, end).iterator();
END OF EDIT
If you really want to implement your own iterator, I would suggest an internal class in this scenario. This way you can access MyArray.this from myIterator.
public class MyArray {
....
private class myIterator implements Iterator{
....
}
}
Its very unusual to maintain an iterator as an instance variable of the class. You can only traverse the array once - probably not what you want. More likely, you want your class to provide an iterator to anyone that wants to traverse your array. A more traditional iterator is below.
Java 5+ code - I haven't tried to compile or run, so it may be contain errors (not near a dev machine right now). It also uses autobox'ing for converting Integer
to int
.
public class MyArray implements Iterable<Integer> {
public static class MyIterator implements Iterator<Integer> {
private final MyArray myArray;
private int current;
MyIterator(MyArray myArray) {
this.myArray = myArray;
this.current = myArray.start;
}
@Override
public boolean hasNext() {
return current < myArray.end;
}
@Override
public Integer next() {
if (! hasNext()) throw new NoSuchElementException();
return myArray.arr[current++];
}
@Override
public void remove() {
// Choose exception or implementation:
throw new OperationNotSupportedException();
// or
//// if (! hasNext()) throw new NoSuchElementException();
//// if (currrent + 1 < myArray.end) {
//// System.arraycopy(myArray.arr, current+1, myArray.arr, current, myArray.end - current-1);
//// }
//// myArray.end--;
}
}
....
// Most of the rest of MyArray is the same except adding a new iterator method ....
public Iterator<Integer> iterator() {
return new MyIterator();
}
// The rest of MyArray is the same ....
}
Also note: be careful of not hitting that 500 element limit on your static array. Consider using the ArrayList class instead if you can.
MyArray should implement the Iterator as it is also responsible for maintaining the array. Simple encapsulation principle.