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);
}
}
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.
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.
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.
Yes, this behavior is deliberate. Here's one way of thinking about it: Set
s are frequently created from other Collection
s, 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, Map
s are typically built from other Map
s, 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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With