2013-04-03 7 views
8

J'ai une classe Java de la forme suivante:Java Iterator pour les types primitifs

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; } 
} 

Je voudrais pouvoir itérer externe sur les données privées en utilisant un itérateur comme ceci:

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

J'ai essayé de mettre en œuvre une classe Iterator privée, mais je suis tombé sur des problèmes:

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 
} 

Comment implémenter un externe itérateur pour les types primitifs (pas génériques)? Est-ce possible en Java?

Répondre

5

Java 8 introduit primitive iterators, qui vous permettent d'éviter la boxe/unboxing lors de l'itération sur int, long et double collections.

Vous pouvez créer votre propre PrimitiveIterator de byte avec la mise en œuvre de type générique PrimitiveIterator<Byte,ByteConsumer>. ByteConsumer doit également être implémenté. Les deux sont assez simples.

Pourquoi n'y a-t-il pas PrimitiveIterator.ofByte dans jdk? Probablement à cause de la taille du mot machine, qui n'est généralement pas plus petit que int. Ou les itérateurs d'octets sont mieux faits par les flux et autres.

+0

Existe-t-il un 'Iterable' analogue pour les types primitifs, donc je peux faire 'for (double d: myContainerWithDoubles) {}'? –

+0

Il n'y a pas d'itérateur primitif pour chaque. La meilleure solution consiste à implémenter 'PrimitiveIterator.OfDouble' et à l'utiliser de manière fonctionnelle. – Oroboros102

8

Un itérateur ne peut pas générer des valeurs d'un type primitif. Cependant, il pourrait donner des valeurs du type de wrapper Byte. De telles valeurs peuvent être auto-unboxed en byte (tant qu'elles ne sont pas null).

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

Ensuite, vous pouvez l'utiliser comme ceci:

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

Je n'étais pas familier avec le concept de l'auto- (dé) boxe. C'est de là que provient ma confusion et où la solution devait être trouvée. –

+0

@awashburn: Voir http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html – NPE

+2

Habituellement, le routage automatique comme ceci est un moyen de générer rapidement beaucoup de déchets.Cependant, pour 'Byte', je crois que la plupart des implémentations Java utilisent un pattern flyweight (puisqu'il n'y a que 256 valeurs' byte'), donc il n'y a pas de fardeau supplémentaire sur le GC. Notez, cependant, que vous devriez utiliser 'for (byte b: instanceOfExample)' - vous ne pouvez pas itérer sur une classe. –

0

Mettre en oeuvre Iterable, et retourner un objet octet au lieu d'un octet primitif:

class Example implements Iterable<Byte> { 

.. 

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

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

mise en œuvre Iterable au lieu de Iterator vous permet faire une boucle sur les éléments de l'objet directement, en utilisant la boucle for-each.

1

Vous ne pouvez pas utiliser de génériques avec des primitives, car les génériques requièrent une classe pour le type.

Qu'est-ce que vous pouvez faire est itérer sur les types de Wrapper (Entier, Byte, booléennes, etc) ...

0

Si vous voulez que votre iterator pour mettre en œuvre java.util.Iterator alors à côté() devra retourner Octet

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(); 
    } 
} 

La suppression peut également être implémentée. Si vous ne avez pas besoin, il Iterator implemnent alors nous pouvons changer suivant() pour revenir octet

class ByteArrayIterator { 
... 
    public byte next() { 
      if (i == a.length) { 
       throw new NoSuchElementException(); 
      } 
      return a[i++]; 
     } 
Questions connexes