views:

258

answers:

4

Hey,

I have a class which uses a HashSet and I want the class implement Iterable, I do not, however, want the class iterator to support the remove() method.

The default iterator of HashSet is HashSet.KeyIterator which is a private class within the HashSet class, so I cannot simply extend it and override the remove method.

Ideally I would like to avoid writing a wrapper class for KeyIterator, but I am at a loss as to how else I could easily and simply implement my own iterator in any other way.

Any ideas?

Cheers,

Pete

+15  A: 
java.util.Collections.unmodifiableSet(myHashSet).iterator();
Brian Clapper
Just be aware that the iterator will return throw an `UnsupportedOperationException` if you try to modify the Set through it.
R. Bemrose
What else what it do?
Steve Kuo
Right. If you want an iterator that silently ignores calls to remove(), you'll have to go with one of the other solutions.
Brian Clapper
One thing to bear in mind is that `Collections.unmodifiableSet()` is a thin wrapper. Changes to myHashSet directly will still be reflected in the unmodifiable collection.
Jherico
+1  A: 

If you're using Apache Commons Collections, you can use org.apache.commons.collections.iterators.UnmodifiableIterator :

UnmodifiableIterator.decorate(set.iterator());

Guava (Google Collections) also has an UnmodifiableIterator, which supports generics: com.google.common.collect.UnmodifiableIterator<E> Usage:

Iterators.unmodifiableIterator(set.iterator());
Chris Lercher
Note, that apache collections don't support generics.
java.is.for.desktop
But it provides a good example, how to implement something like that... :-)
Chris Lercher
...or you can look at `com.google.common.collect.UnmodifiableIterator<E>`
Chris Lercher
A: 

Use the Composite pattern: create a new implementation of the Iterator interface that is a wrapper around the iterator from the HashSet, but instead of passing through calls to remove throw an UnsupportedOperationException.

Hank Gay
A valid answer but I explicitly asked for an alternative solution.
Peter
@Peter You're right. I apparently fail at reading comprehension.
Hank Gay
A: 

Creating the wrapper using an anonymous inner class is fairly simple:

See this example:

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 );
        }

    }
}

You may also throw UnsupportedOperationException if you want to explicitly declare that the operation is not supported, but It may be a little excessive.

OscarRyz