views:

109

answers:

5

I obtain a HashSet from a HashMap and I don't want that my modifications on the HashSet reflect on the HashMap values.

What's the best way of doing something like this :

HashSet<Object> hashset = new HashSet((Collection<Object>) hashmap.values());
//Something like ...
hashset.detach();
//Then i can modify the HashSet without modifying the HashMap values

Edit : I have to modify an element in the HashSet but I don't want to modify this same element in the HashMap.

Thanks!!!

+7  A: 

If you're creating a new HashSet as per the first line of your code snippet, that's already a separate collection. Adding or removing items from the set won't change your hashMap. Modifying the existing items will, of course - but that's a different matter, and will almost always be a Very Bad Thing (assuming your modifications affect object equality).

Jon Skeet
+1  A: 

You are close:

Set<Object> set =  hashmap.values(); // is backed by the map

// create a new hashset seeded from the other set
Set<Object> hashset = new HashSet<Object>(set);
Gareth Davis
It don't work .. the modification of an element is reflected in the HashMap.
elblanco
Then you are changing elements within the set (rather than changing *which* elements are in the set). For this, you need to copy each element into the new set, as others have said.
Carl Manaster
+4  A: 

When you create the HashSet from hashMap.values() like this, then it's already "detached" in the sense that modifying the HashSet will not influence the map it was constructed from.

However, if you modify an object inside the set (for example calling a setter on it), then those changes will be reflected inside the HashMap as well (since the Set and the Map will refer to the same object).

One way around this is to make defensive copies of each element (using clone() or by using a copy constructor).

Another way is to use immutable objects.

Joachim Sauer
Using clone() or new HashSet<Object>(object) don't work .. the modification of an element is reflected in the HashMap.
elblanco
@elbanco: I meant that you use `clone()` on *each element in the `Set`*. If you only clone the `Set` itself, then that will have no effect.
Joachim Sauer
ok ... I will give it a try after lunch.
elblanco
I cloned each element one by one and it works. Thank you.
elblanco
A: 

If you are trying to copy the values, and change the state of the values you need to create a deep copy, which relies on knowing how to create copies of the objects held in the Map as values. Hopefuly this test illustrates what I mean.

@Test
public void testHashMap() throws Exception {
    final Map<Integer, TestContainer<Double>> hashmap = new HashMap<Integer, TestContainer<Double>>();
    final TestContainer<Double> t1 = new TestContainer<Double>(1d);
    final TestContainer<Double> t2 = new TestContainer<Double>(2d);
    hashmap.put(1, t1);
    hashmap.put(2, t2);

    // create a separate collection which can be modified
    final Set<TestContainer<Double>> hashset = new HashSet<TestContainer<Double>>(hashmap.values());
    assertEquals(2, hashmap.size());
    assertEquals(2, hashset.size());

    hashset.remove(t2);

    assertEquals(2, hashmap.size());
    assertEquals(1, hashset.size());

    // prove that we cannot modify the contents of the collection
    hashset.iterator().next().o += 1;

    assertEquals(2d, t1.o, 0d);
}

private static final class TestContainer<T> {
    private T o;

    private TestContainer(final T o) {
        this.o = o;
    }
}
Jon Freedman
A: 

Try this:

public MyType cloneObject(MyType o) {
    MyType clone = new MyType();
    // TODO copy the attributes of 'o' to 'clone' return the clone
    return clone; 
}

public void populateHashSet(HashMap<Object,MyType> hashMap) {
    HashSet<MyType> hashSet = new HashSet<MyType>();
    for (MyType o : hashMap.values()) {
        hashSet.add(cloneObject(o));
    }
}

That said, I would be very careful about making copies of objects unless all the attributes of the object are primitive/immutable types. If you just copy an attribute object reference to an object reference in the clone then your 'clone' can still produce side-effects in the original object by changing the objects it references.

Jim Tough