2009-05-04 9 views
26

En Java, necesito devolver un iterador de mi método. Mis datos provienen de otro objeto que generalmente me puede dar un iterador, así que puedo devolverlo, pero en algunas circunstancias los datos subyacentes son nulos. Por coherencia, quiero devolver un iterador "vacío" en ese caso para que las personas que llaman no tengan que probar nulo.iterador de Java sobre una colección vacía de un tipo parametrizado

que quería escribir algo como:

public Iterator<Foo> iterator() { 
    if (underlyingData != null) { 
     return underlyingData.iterator(); // works 
    } else { 
     return Collections.emptyList().iterator(); // compiler error 
    } 
} 

Pero el compilador de Java se queja de la Iterator<Object> en lugar de regresar Iterator<Foo>. Casting a (Iterator<Foo>) tampoco funciona.

Respuesta

56

, usted puede obtener una lista vacía de tipo Foo través de la siguiente sintaxis:

return Collections.<Foo>emptyList().iterator(); 
+0

Acabo de descubrir que, a veces, tratar de ser rápido le ralentiza. Escribí una implementación de Iterador vacío y volví aquí para encontrar que había estado en un camino de conejito. +1 –

+2

En Java 1.7 Colecciones API se extendió con 'Collections.emptyIterator()'. –

0

Lo sentimos, lo he descubierto. Necesita usar una asignación para que el compilador pueda descifrar el tipo parametrizado.

public Iterator<Foo> iterator() { 
    if (underlyingData != null) { 
     return underlyingData.iterator(); 
    } else { 
     List<Foo> empty = Collections.emptyList(); // param type inference 
     return empty.iterator(); 
    } 
} 
+0

Wow, Alex B respondió incluso antes de que pudiera escribir mi solución. Me faltaba la sintaxis para el tipo parametrizado devuelto por emptyList(). La asignación funciona, pero el trazador de líneas uno es aún mejor. – miner49r

9

me gustaría ir más a lo largo de las líneas de

public Iterator<Foo> iterator() { 
    if (underlyingData == null) 
     return Collections.<Foo> emptyList().iterator(); 
    return underlyingData.iterator(); 
} 

Así, manejar el caso especial y devolución, y luego manejar el caso normal. Pero mi punto principal es que se puede evitar la asignación con

Collections.<Foo> emptyList().iterator(); 
+0

+1 para manejar solo el caso especial y eliminar 'else' –

+0

IMO, nulo y no nulo son igualmente especiales en este caso. lo demás está más claro aquí. –

+0

Tienes derecho a YO, por supuesto, pero a mí me parece que esta clase trata todas las listas, incluida la lista vacía, como si (esta clase) fuera la lista, eso es flujo normal, para mí, pero está tratando nulo especialmente, como si fuera la lista vacía, que no lo es. Delega normalmente a los datos subyacentes y fabrica algo especial cuando no puede. –

2

supongo que esto demuestra que la inferencia de tipos de Java no funciona en todos los casos y que el operador ternario no siempre es equivalente al parecer equivalentes si-else construir.

También quiero indicar evitar null. También evite pasar Iterator s, porque tienen un comportamiento de estado extraño (prefiera Iterable). Sin embargo, suponiendo que tiene una razón legítima, no prematuro para hacer esto, mi forma preferida de escribir sería

public Iterator<Foo> iterator() { 
    return getUnderlyingData().iterator(); 
} 
private List<Foo> getUnderlyingData() { 
    if (underlyingData == null) { 
     return Collections.emptyList(); 
    } else { 
     return underlyingData; 
    } 
} 

OMI, es mejor no introducir la información de tipo inferirse si se puede inferir (incluso si hace que tu código sea más largo).

Seguramente va a hacerlo más de una vez, por lo tanto, inserte un método getUnderlyingData en lugar de simplemente declarar una variable local.

Está llamando al iterator en ambos resultados, así que no se repita.

+0

+1 para el DRY win solo del iterador que llama() desde un solo lugar. Me pregunto si este tipo de solución podría trasladarse a donde se modifique el subyacenteData, esto sería lo más DRYest de todo lo que pienso. – CurtainDog

4

La molestia de Collections.<Foo>emptyList().iterator() es la razón principal por la que proporcionamos Iterators.emptyIterator() en google-collections. No se necesita ningún parámetro de tipo, en casos como el tuyo.

0
public final class EmptyIterator{ 

    public static Iterator iterator(){ 
     return new Empty(); 
    } 

    private static class Empty implements Iterator { 
     public boolean hasNext(){ 
      return false; 
     } 
     public Object next(){ 
      throw new NoSuchElementException(); 
     } 
     public void remove(){ 
     } 
    } 
} 
+0

Hay un iterador incorporado que hace lo mismo: 'Collections.emptyIterator();'. – assylias

25

Java 7 ha estado fuera por mucho tiempo. A menos que esté desarrollando para una versión anterior de Java, devolvería un iterador vacío como este:

return Collections.emptyIterator(); 
+1

También puede parametrizar su iterador vacío: 'Colecciones. emptyIterator() ' – Thomas

Cuestiones relacionadas