2013-04-03 49 views
12

Ponieważ Java 5, mamy nową java.lang.Iterable typ, który może być używany w pętli foreach jako takie:Czy jest jakiś oficjalny kontrakt dotyczący interfejsu Iterable w odniesieniu do wielokrotnego użycia?

for (Object element : iterable); 

Umowa Iterable nie precyzuje, czy jego metoda iterator() można nazwać więcej niż raz przed utylizacją iterowalny . To znaczy, że nie jest jasne, czy można oczekiwać, dodaje do pracy dla wszystkich Iterables:

for (Object element : iterable); 
for (Object element : iterable); 

Na przykład, implementacja Iterator opakowanie nie może być użyty dwukrotnie:

public class OneShotIterable<T> implements Iterable<T> { 
    private final Iterator<T> it; 

    public OneShotIterable(Iterator<T> it) { 
     this.it = it; 
    } 

    @Override 
    public Iterator<T> iterator() { 
     return it; 
    } 
} 

Dla większości Iterables, to jest nieistotne, ponieważ w rzeczywistości są to retro-dopasowane interfejsy API kolekcji, takie jak List, Set, które mają już dobrze zdefiniowane umowy na swoje metody iterator().

Moje pytanie brzmi: czy moja implementacja OneShotIterable narusza jakąś umowę, z której nie korzystam? Innymi słowy, czy użytkownicy urządzenia Iterable oczekują, że będzie on możliwy do ponownego użycia? Jeśli tak, czy istnieje "oficjalne" zalecenie grupy ekspertów Java 5, jak radzić sobie z takim "jednym ujęciem" Iterables (np. Wyrzucać IllegalStateException przy drugim wywołaniu)?

+2

+1 za wymierny – TheBlastOne

+0

Nie możesz po prostu zwiększyć pola OneShotIterable za każdym razem, gdy iterator() zostanie wywołany, i wyrzucić wyjątek, jeśli to jest gte n? – sp00m

+0

@LukasEder doh edytowałeś to – TheBlastOne

Odpowiedz

14

Jednym z precedensów, które mogłem znaleźć w standardowej bibliotece, jest interfejs DirectoryStream.

Jego Javadoc zawiera następujące przejścia (podkreślenia ich kompetencji):

Podczas DirectoryStream rozciąga Iterable, nie jest ogólnego przeznaczenia Iterable ponieważ obsługuje tylko pojedynczy Iterator; wywołanie metody iterator w celu uzyskania drugiego lub kolejnego iteratora wyrzuca IllegalStateException.

Dla mnie to sugeruje dwie rzeczy: (! Może nawet jednocześnie)

  • implikowana kontrakt na Iterable jest to, że powinniśmy być w stanie iteracyjne więcej niż raz
  • A ostrzeżenie pogrubione ostrzeżenie w dokumentacji w połączeniu z rzucaniem IllegalStateException jest prawdopodobnie najlepszym sposobem na poradzenie sobie z niezgodnościami we własnych klasach/interfejsach.