How to implement iterator as an attribute of a class in Java

后端 未结 6 942
既然无缘
既然无缘 2020-12-17 04:19

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:



        
相关标签:
6条回答
  • 2020-12-17 04:38

    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.

    0 讨论(0)
  • 2020-12-17 04:44

    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());
      }
    
     }
    
    }
    
    0 讨论(0)
  • 2020-12-17 04:47

    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
        }
    }
    
    0 讨论(0)
  • 2020-12-17 04:47

    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{
            ....
        }
    }
    
    0 讨论(0)
  • 2020-12-17 04:49

    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.

    0 讨论(0)
  • 2020-12-17 04:56

    MyArray should implement the Iterator as it is also responsible for maintaining the array. Simple encapsulation principle.

    0 讨论(0)
提交回复
热议问题