2010-06-18 8 views
6

Mam klasę, która używa HashSet i chcę klasy implementacji Iterable, nie chcę jednak, aby iterator klasy obsługiwał metodę remove().Java - HashSet najlepszy sposób na implementację iteratora, który nie obsługuje remove()

Domyślny iterator HashSet to HashSet.KeyIterator, który jest prywatną klasą w klasie HashSet, więc nie mogę go po prostu rozszerzyć i nadpisać metody remove.

Idealnie chciałbym uniknąć pisania klasy opakowania dla KeyIterator, ale nie mam pojęcia, jak inaczej mógłbym łatwo i po prostu wdrożyć mój własny iterator w jakikolwiek inny sposób.

Wszelkie pomysły?

Cheers,

Pete

+0

Czy Twój HashSet muszą być modyfikowalne? –

+0

@Kevin Tak, ale musi również zachować spójną liczbę elementów, którymi zarządza wewnętrzna logika klasy, ale nie jest czymś, co chciałbym zostawić, aby zaufać, jeśli HashSet zostanie zmodyfikowany za pomocą iteratora. – Peter

+0

Co jest złego w opakowaniu? – whiskeysierra

Odpowiedz

16
java.util.Collections.unmodifiableSet(myHashSet).iterator(); 
+4

Pamiętaj, że iterator zwróci wyjątek 'UnsupportedOperationException', jeśli spróbujesz zmodyfikować Zestaw przez niego. – Powerlord

+0

Co jeszcze robi? –

+0

W prawo. Jeśli chcesz iteratora, który po cichu ignoruje wywołania do usunięcia(), musisz przejść z jednym z innych rozwiązań. –

1

Jeśli używasz Apache Commons kolekcje, można użyć org.apache.commons.collections.iterators.UnmodifiableIterator :

UnmodifiableIterator.decorate(set.iterator()); 

Guava Kolekcje (Google) posiada również UnmodifiableIterator, który obsługuje ogólne: com.google.common.collect.UnmodifiableIterator<E> Użycie:

Iterators.unmodifiableIterator(set.iterator()); 
+0

Należy zauważyć, że kolekcje apache nie obsługują generycznych. –

+0

Ale daje dobry przykład, jak zaimplementować coś takiego ... :-) –

+2

...lub możesz spojrzeć na 'com.google.common.collect.UnmodifiableIterator ' –

-1

Użyj Composite pattern: utworzyć nową implementację interfejsu Iterator że jest opakowaniem wokół iterator od HashSet, ale zamiast przejazdem połączeń do remove rzucić UnsupportedOperationException.

+0

Poprawna odpowiedź, ale wyraźnie poprosiłem o alternatywne rozwiązanie. – Peter

+0

@Peter Masz rację. Najwyraźniej nie potrafię czytać ze zrozumieniem. –

0

Tworzenie opakowanie korzystając anonimową klasę wewnętrzną jest dość prosta:

Zobacz ten przykład:

package some; 
import java.util.Set; 
import java.util.HashSet; 
import java.util.Iterator; 

class MyIterable<E> implements Iterable<E> { 
    private Set<E> internalSet = new HashSet<E>(); 

    public MyIterable(E ... all) { 
     for(E e : all){ 
      internalSet.add(e); 
     } 
    } 

    public Iterator<E> iterator() { 
     final Iterator<E> i = internalSet.iterator(); 
     return new Iterator<E>() { 
      public boolean hasNext(){ 
       return i.hasNext(); 
      } 
      public E next(){ 
       return i.next(); 
      } 
      public void remove(){ 
       //you may throw new UnsupportedOperationException(); 
      } 
     }; 
    } 

    // Test it 
    public static void main(String [] args) { 
     Iterable<String> iterable = new MyIterable<String>("a", "b", "a", "b"); 

     System.out.println("Trying to invoke: remove"); 
     for(Iterator<String> iterator = iterable.iterator(); 
             iterator.hasNext(); 
             iterator.remove()){ 
       System.out.println(iterator.next()); 
     } 
     System.out.println("Used in foreach"); 
     for(String s : iterable){ 
      System.out.println(s); 
     } 

    } 
} 

Można też rzucać UnsupportedOperationException jeśli chcesz jawnie zadeklarować, że operacja nie jest obsługiwana, ale To może być trochę przesadzone.

1

Poniżej jest jednym ze sposobów, które możemy uniknąć tych rodzaju wyjątki podczas usuwania elementów z iteracyjnej

List<String> results=new ArrayList<String>() //a collection 
Iterator<String> itr=results.iterator(); 
List<String> toBeRemoved=new ArrayList<String>(); 

while(itr.hasNext()){ 
    if(condiation){ 
     tobeRemoved.add(itr.next); 

    } 
} 
//now we can remove unnecessary elements form the iterator 
results.removeAll(toBeRemoved); 

Tego rodzaju wdrożeń jest gwarancja, że ​​nie ma wyjątków w modyfikując iterator

Powiązane problemy