Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ImmutableSet allow duplicates, but ImmutableMap does not

I noticed (and appreciated!) that Guava's ImmutableMap.Builder fails to build if duplicate keys have been added to the builder. Yet the same behavior (adding duplicate elements) succeeds with ImmutableSet.

Is there a reason for this difference, and any good way to construct an ImmutableSet with the same failure behavior?

Test case:

import static org.testng.Assert.*;
import org.testng.annotations.Test;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

public class ImmutableDuplicatesTest
{
    @Test(expectedExceptions=IllegalArgumentException.class) // Note failure
    public void mapDuplicates() {
        ImmutableMap.Builder<String, String> map = ImmutableMap.builder();
        map.put("a", "a");
        map.put("b", "b");
        map.put("a", "c");
        assertEquals(map.build().size(), 2);
    }

    @Test // Passes normally
    public void setDuplicates() {
        ImmutableSet.Builder<String> set = ImmutableSet.builder();
        set.add("a");
        set.add("b");
        set.add("a");
        assertEquals(set.build().size(), 2);
    }
}
like image 869
dimo414 Avatar asked Nov 04 '13 17:11

dimo414


People also ask

Is ImmutableMap ordered?

To be more precise, the ImmutableMap factory methods and builder return instances that follow the iteration order of the inputs provided when the map in constructed.

What is ImmutableMap?

ImmutableMap, as suggested by the name, is a type of Map which is immutable. It means that the content of the map are fixed or constant after declaration, that is, they are read-only. If any attempt made to add, delete and update elements in the Map, UnsupportedOperationException is thrown.

Is set immutable in Java?

One advantage of any immutable collection (Set, Map, List) is thread safety. These are automatically thread sage as they are immutable. Note that it is an immutable collection, not collection of immutable objects, so the objects inside it can be modified.


1 Answers

Yes, this behavior is deliberate. Here's one way of thinking about it: Sets are frequently created from other Collections, especially List, which may have duplicates. It'd be very awkward -- and inefficient -- to require users to write ImmutableSet.copyOf(Sets.newHashSet(element)) if there might be duplicates. On the other hand, Maps are typically built from other Maps, which can't have duplicate keys.

If you want to forbid duplicate elements, your best bet is something like

Set<E> set = new LinkedHashSet<E>();
for (E e : input) {
  if (!set.add(e)) {
    throw new IllegalArgumentException();
  }
}
return ImmutableSet.copyOf(set);
like image 66
Louis Wasserman Avatar answered Oct 17 '22 21:10

Louis Wasserman