2011-04-29 17 views
14

estoy tratando de entender Java Iterator y Iterable interfaces de¿Implementar Java Iterator e Iterable en la misma clase?

Estoy escribiendo esta clase

class MyClass implements Iterable<String> { 
    public String[] a = null; 
    public MyClass(String[] arr) { 
     a = arr;  
    } 

    public MyClassIterator iterator() { 
     return new MyClassIterator(this); 
    } 

    public class MyClassIterator implements Iterator<String> { 
     private MyClass myclass = null; 
     private int count = 0; 
     public MyClassIterator(MyClass m) { 
      myclass = m;  
     } 

     public boolean hasNext() { 
      return count < myclass.a.length; 
     } 
     public String next() { 
      int t = count; 
      count++; 
      return myclass.a[t]; 
     } 

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

Parece estar funcionando.

¿Debo tener:

Myclass implements Iterable<Stirng>, Iterator<String> { 

} 

O debo poner MyClassIterator fuera MyClass como

class MyClass implements Iterable<String> { 
    public String[] a = null; 
    public MyClass(String[] arr) { 
     a = arr;  
    } 
    public MyClassIterator iterator() { 
     return new MyClassIterator(this); 
    } 
} 


    public class MyClassIterator implements Iterator<String> { 
     private MyClass myclass = null; 
     private int count = 0; 
     public MyClassIterator(MyClass m) { 
      myclass = m;  
     } 

     public boolean hasNext() { 
      return count < myclass.a.length; 
     } 
     public String next() { 
      int t = count; 
      count++; 
      return myclass.a[t]; 
     } 

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

¿Cuál es mejor?

+1

¿Por qué tiene que hacer tanto para su clase? En general, implementará Iterable para que alguien pueda obtener un iterador de su clase. – Kal

Respuesta

31

Usted debe casi nunca implementar Iterable y Iterator en la misma clase. Ellos hacen cosas diferentes. Un iterador es naturalmente stateful - a medida que itera al usarlo, tiene que actualizar su vista del mundo. Un iterable, sin embargo, solo necesita poder crear nuevos iteradores. En particular, podría tener varios iteradores trabajando sobre el mismo iterable original al mismo tiempo.

Su enfoque actual está bastante bien, hay aspectos de la implementación que cambiaría, pero está bien en términos de separación de responsabilidades.

+0

gracias, he actualizado un poco mi pregunta, cuál es mejor, ¿qué tal si pongo MyClassInterator fuera de MyClass? – icn

+2

@icn: Mantener MyClassIterator como una clase anidada está bien. (No obstante, el iterador no es Interator). Sin embargo, sugiero que sea una clase privada estática privada. Después de todo, no es necesario que pueda consultarlo directamente desde ningún otro lugar. –

+0

@icn: Debería mantener 'MyClassIterator' dentro de' MyClass'. También debe hacerlo 'private' y hacer que el método devuelva' Iterator '. Tampoco debe pasar 'MyClass' al constructor porque' MyClassIterator' es una clase interna y tiene una referencia implícita a la instancia circundante de 'MyClass', por lo que puede acceder directamente a la matriz' a' directamente en él. – ColinD

2

No debe hacer Myclass implements Iterable<String>,Iterator<String>{ ya que los iteradores son de un solo uso. Con la excepción de los iteradores de listas, no hay forma de devolverlos al inicio.

Por cierto, se puede omitir el

MyClass myClass; 
public MyClassInterator(MyClass m){ 
    myclass=m; 
} 

y en lugar de hacer referencia a

myClass 

referencia

MyClass.this 

Su clase interna no es estático, por lo MyClass.this hará referencia a la instancia de la clase adjunta que lo creó.

7

Estabas en camino con tu primer intento. MyClass solo necesita implementar Iterable<String>, que a su vez requiere que proporcione una implementación Iterator<String> para devolver desde Iterable<String>.iterator().

No hay necesidad de poner el exterior MyClassIterator de MyClass porque en la mayoría de los casos usted nunca tenga que utilizar directamente el Iterator<String> (se utiliza implícitamente por la sintaxis for .. in .. en Iterable<String> s), y en todos los demás casos, la interfaz es suficiente a menos que realmente agregue un comportamiento adicional a la implementación (que probablemente nunca tendrá que hacer).

Así es como yo lo haría, ver los comentarios entre líneas:

import java.util.Iterator; 

class MyClass implements Iterable<String>{ 
    public String[] a=null; //make this final if you can 
    public MyClass(String[] arr){ 
     a=arr; //maybe you should copy this array, for fear of external modification 
    } 

    //the interface is sufficient here, the outside world doesn't need to know 
    //about your concrete implementation. 
    public Iterator<String> iterator(){ 
     //no point implementing a whole class for something only used once 
     return new Iterator<String>() { 
      private int count=0; 
      //no need to have constructor which takes MyClass, (non-static) inner class has access to instance members 
      public boolean hasNext(){ 
       //simplify 
       return count < a.length; 
      } 
      public String next(){ 
       return a[count++]; //getting clever 
      } 

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

Gracias, ya que tenemos una excepción "lanzar nueva UnsupportedOperationException();", en algún lugar del programa debemos especificar que una excepción arrojar algo como throw UnsupportedOperationException()? – icn

+0

Su bienvenida, @icn. Sí, probablemente sea suficiente mencionarlo en los comentarios para 'iterator()'. En la práctica no importará, 'for .. in ..' es prácticamente la única construcción que hace uso directo de' Iterator's en Java (moderno) y no intenta usar 'remove'. De hecho, los miembros de la interfaz "opcional" como "eliminar" son inútiles en el mejor de los casos, ya que los consumidores tienen que asumir que arrojarán. –

Cuestiones relacionadas