How to implement an iterator as a class attribute in Java

let's say I have this simple MyArray class with two simple methods: add, delete, and iterator. In the main method, we see how it should be used:

public class MyArray { int start; int end; int[] arr; myIterator it; public MyArray(){ this.start=0; this.end=0; this.arr=new int[500]; it=new myIterator(); } public void add(int el){ this.arr[this.end]=el; this.end++; } public void delete(){ this.arr[this.start]=0; this.start++; } public static void main(String[] args){ MyArray m=new MyArray(); m.add(3); m.add(299); m.add(19); m.add(27); while(m.it.hasNext()){ System.out.println(m.it.next()); } } 

And then MyIterator should be implemented somehow:

 import java.util.Iterator; public class myIterator implements Iterator{ @Override public boolean hasNext() { // TODO Auto-generated method stub return false; } @Override public Object next() { // TODO Auto-generated method stub return null; } @Override public void remove() { // TODO Auto-generated method stub } 

}

MyIterator must iterate arr from the MyArray class, from start to finish; both are attributes of MyArray. So, since MyIterator should use MyArray attributes, how should MyIterator be implemented? Perhaps I can send the current object to initialization:

 it=new myIterator(this); 

But I think this is not the best soul. Or maybe MyArray should implement the Iterator interface? How to solve this?

EDIT:

Ok, thanks everyone. This was a simple example of what I should do, so it doesn't care about a fixed-length array. Waht, I really want to make a circular FIFO, so start and end are cursors.

This round FIFO will be an array of int pairs with, for example, a size of 300: int[][] arr=new int[300][2] .

When repeating a circular array, I have to take care of whether the counter fits the end and start it from the very beginning, so this is how I solved it:

 if (this.start >= this.end ) temp_end=this.end+this.buff.length; else temp_end=this.end; int ii; int j=0; int[] value=new int[2]; for(int i=this.start; i<temp_end; i++){ ii=i% this.arr.length; value=this.buff[ii]; //do anything with value 

}

But I would like not to worry about these things and just iterate over a simple way, I can do it using the iterator interface, but then I have two problems: the first of which I already explained and was solved by many answers, and the second is that my array consists of pairs of ints, and I cannot use an iterator with primitive types.

+4
source share
6 answers

It is very unusual to maintain an iterator as an instance variable of a class. You can only move through the array once โ€” perhaps not what you want. Most likely, you want your class to provide the iterator to anyone who wants to traverse your array. More traditional iterator below.

Java 5+ code - I did not try to compile or run, so it may contain errors (not right next to the dev machine). It also uses autobox'ing to convert 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 not to put a limit of 500 elements on your static array. Instead, consider using the ArrayList class if you can.

+8
source

In my opinion, it is better to implement MyArray as a regular Iterable object, so it can be used in the 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 } } 
+4
source

Iterator is an interface. Iterator<E> , which means only the object (E). Iterator<Integer> is legal, but Integer<int> not because int is a primitive data type

You can change the array to ArrayList and then iterate over this arraylist. I added the getIterator() method, which returns arraylist.iterator() and tests it in the 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()); } } } 
+2
source

My suggestion is to allow MyArray implement the java.lang.Iterable interface and create an iterator instance by calling iterator() (as an anonymous class). Then you can use the MyArray instance directly in the 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: Following BertF's comment, I updated my code so that it is clear that the only instance variable for the MyArray class is now arr . The iterator state is now in an anonymous Iterator implementation. This way you can create multiple instances of the iterator that do not interfere with each other.

+2
source

EDIT: this does not work for arrays of primitive types: you can use arrays for this:

it = new Arrays.asList(arr).subList(start, end).iterator(); END OF CHANGE

If you really want to implement your own iterator, I would suggest an inner class in this scenario. This way you can access MyArray.this from myIterator.

 public class MyArray { .... private class myIterator implements Iterator{ .... } } 
+1
source

MyArray must implement Iterator, as it is also responsible for maintaining the array. The simple principle of encapsulation.

0
source

Source: https://habr.com/ru/post/1333388/


All Articles