Question

I have a Java class of the following form:

class Example {

  private byte[][] data;

  public Example(int s) { data = new byte[s][s]; }

  public byte getter(int x, int y)         { return byte[x][y]; }
  public void setter(int x, int y, byte z) { byte[x][y] = z;    }
}

I would like to be able to externally iterate over the private data using an iterator like so:

for(byte b : Example) { ;/* do stuff */ }

I tried to implement a private Iterator class but I ran into problems:

private class ExampleIterator implements Iterator {
  private int curr_x;
  private int curr_y;

  public ExampleIterator() { curr_x=0; curr_y=-1; }
  public boolean hasNext() { 
    return curr_x != field.length-1
        && curr_y != field.length-1; //is not the last cell?
  }
  public byte next() { // <-- Error is here: 
                       // Wants to change return type to Object
                       // Won't compile!
    if(curr_y=field.length) { ++curr_x; curr_y=0; }
    return field[curr_x][curr_y];
  }
  public void remove() { ; } //does nothing
}

How would I implement an external iterator for primitive types (not generics)? Is this possible in Java?

Was it helpful?

Solution 2

Java 8 introduced primitive iterators, that allow you to avoid boxing/unboxing during iteration over int, long and double collections.

You can create you own PrimitiveIterator of byte with typesafely implementing generic PrimitiveIterator<Byte,ByteConsumer>. ByteConsumer is also to be implemented. Both are pretty straightforward.

Why is there no PrimitiveIterator.ofByte in jdk? Probably because of machine word size, that is usually not smaller than int. Or byte iterators are better done by streams and such.

OTHER TIPS

An iterator cannot yield values of a primitive type. However, it could yield values of the wrapper type Byte. Such values can be auto-unboxed into byte (as long as they are not null).

private class ExampleIterator implements Iterator<Byte> {
  public boolean hasNext() { ... }
  public Byte next() { ... }
}

Then you can use it like so:

for (byte b : example) { ... }

You can't use generics with primitives, as the generics require a class for the type.

What you can do is iterate over the Wrapper types (Integer, Byte, Boolean, etc)...

Implement Iterable, and return a Byte object instead of a byte primitive:

class Example implements Iterable<Byte> {

..

    public Iterator<Byte> iterator() {
        return new MyIterator();
    }

    private class MyIterator implements Iterator<Byte> {
        public Byte next() {...}
        ....
    }
}

Implementing Iterable instead of Iterator allows you to loop on the object items directly, using the for-each loop.

If you want your iterator to implement java.util.Iterator then next() will have to return Byte

class ByteArrayIterator implements Iterator<Byte> {
    final byte[] a; 
    int i = 0;
    ByteArrayIterator(byte[] a) {
        this.a = a; 
    }

    public boolean hasNext() {
        return i < a.length;
    }

    public Byte next() {
        if (i == a.length) {
            throw new NoSuchElementException();
        }
        return a[i++];
    }

    public void remove() {
        throw new UnsupportedOperationException();
    }
}

remove can be implemented too. If you dont need it implemnent Iterator then we can change next() to return byte

    class ByteArrayIterator {
...
    public byte next() {
            if (i == a.length) {
                throw new NoSuchElementException();
            }
            return a[i++];
        }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top