2009-05-04 15 views
26

In Java, ho bisogno di restituire un Iterator dal mio metodo. I miei dati provengono da un altro oggetto che di solito può darmi un iteratore, quindi posso solo restituirlo, ma in alcune circostanze i dati sottostanti sono nulli. Per coerenza, voglio restituire un iteratore "vuoto" in quel caso in modo che i miei chiamanti non debbano verificare nulla.iteratore Java su una raccolta vuota di un tipo parametrizzato

volevo scrivere qualcosa di simile:

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

Ma il compilatore Java si lamenta del ritorno Iterator<Object> invece di Iterator<Foo>. Il casting su (Iterator<Foo>) non funziona neanche.

risposta

56

è possibile ottenere un elenco vuoto di tipo Foo attraverso la seguente sintassi:

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

Ho appena scoperto che a volte il tentativo di essere veloce rallenta. Avevo scritto un'implementazione di Iterator vuota e sono tornato qui per scoprire che ero stato su una pista di coniglietto. +1 –

+2

Nell'API Java 1.7 Collections è stato esteso con 'Collections.emptyIterator()'. –

0

Scusa, ho capito. È necessario utilizzare un'assegnazione in modo che il compilatore possa capire il tipo parametrizzato.

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 ha risposto ancora prima che potessi digitare la mia soluzione. Mi mancava la sintassi per il tipo parametrico restituito da emptyList(). L'incarico funziona, ma l'unica è ancora meglio. – miner49r

9

Mi piacerebbe andare più lungo le linee di

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

Basta, gestire il caso speciale e ritorno, quindi gestire il caso normale. Ma il mio punto principale è che si può evitare l'assegnazione con

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

+1 per la gestione solo del caso speciale e la rimozione di 'else' –

+0

IMO, null e non null sono ugualmente speciali in questo caso. altrimenti è più chiaro qui. –

+0

Hai diritto a YO, naturalmente, ma a me sembra che questa classe tratti tutte le liste, inclusa la lista vuota, come se (questa classe) fosse la lista - questo è il flusso normale, per me - ma tratta null specialmente - come se fosse la lista vuota, che non è. Delegando normalmente i dati sottostanti e producendo qualcosa di speciale quando non è possibile. –

2

Credo che questo dimostra che l'inferenza dei tipi Java non funziona in tutti i casi e che l'operatore ternario non è sempre equivalente alla apparentemente equivalente if-else costruire.

Desidero anche specificare evitare null. Evita anche di passare circa Iterator s, perché hanno uno strano comportamento di stato (preferisci Iterable). Tuttavia, a patto di avere un motivo legittimo, non prematuro per fare questo, il mio modo preferito di scrivere sarebbe

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

IMO, è meglio non inserire le informazioni sul tipo desumibili se si può dedurre (anche se rende il tuo codice più lungo).

Quasi certamente lo farete più di una volta, quindi inserite un metodo getUnderlyingData invece di dichiarare una variabile locale.

Stai chiamando iterator in entrambi i risultati, quindi non ripeterti.

+0

+1 per la vittoria di DRY da solo chiamata iterator() da un posto. Mi chiedo se questo tipo di soluzione possa essere spostata nel punto in cui i dati sottostanti vengono modificati - questo sarebbe il più DESTRO di tutto ciò che penso. – CurtainDog

4

Il fastidio di Collections.<Foo>emptyList().iterator() è il motivo principale per cui forniamo Iterators.emptyIterator() in google-collections. Nessun parametro di tipo necessario, in casi come il tuo.

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

C'è un iteratore incorporato che fa lo stesso: 'Collections.emptyIterator();'. – assylias

25

Java 7 è fuori da molto tempo. A meno che tu non stia sviluppando per una versione precedente di Java, restituiresti un iteratore vuoto come questo:

return Collections.emptyIterator(); 
+1

Puoi anche parametrizzare il tuo iteratore vuoto: 'Collezioni. emptyIterator() ' – Thomas

Problemi correlati