Java Iterator for primitive types
Asked Answered
C

5

9

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?

Coley answered 3/4, 2013 at 15:11 Comment(0)
R
8

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.

Revis answered 28/6, 2015 at 16:18 Comment(2)
Is there an analogue Iterable for primitive types, so I can do for(double d : myContainerWithDoubles) {} ?Nebuchadnezzar
There is no for-each primitive iterator. Best match is to implement PrimitiveIterator.OfDouble and use it in functional fashion.Revis
C
8

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) { ... }
Champaigne answered 3/4, 2013 at 15:13 Comment(3)
I was unfamiliar with the concept of auto-(un)boxing. This is where my confusion stemmed from and where the solution was to be found.Coley
Normally autoboxing like this is a way to generate a lot of garbage quickly. However, for Byte, I believe that most Java implementations use a flyweight pattern (since there are only 256 byte values), so there isn't an extra burden on the GC. Note, however, you'd have to use for (byte b : instanceOfExample) -- you can't iterate over a class.Teahouse
@TedHopp Thank you for the technical insight, knowing what happens "behind the curtain" is always valuable!Coley
R
8

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.

Revis answered 28/6, 2015 at 16:18 Comment(2)
Is there an analogue Iterable for primitive types, so I can do for(double d : myContainerWithDoubles) {} ?Nebuchadnezzar
There is no for-each primitive iterator. Best match is to implement PrimitiveIterator.OfDouble and use it in functional fashion.Revis
L
1

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)...

Laoighis answered 3/4, 2013 at 15:15 Comment(0)
T
0

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.

Tabanid answered 3/4, 2013 at 15:14 Comment(0)
L
0

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++];
        }
Lull answered 3/4, 2013 at 15:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.