1

I've just encountered a crash caused by adding duplicate entries to the java.util.Set.of(...) method added in Java 9.

Reading the method's documentation it is clear that such a crash can occur (shame on me), but I find this behavior counter-intuitive compared to the familiar behavior of a Set to prevent duplicate entries 'behind the scenes'.

Set<String> set;

// set will only contain the one element "foo"
set = new HashSet<>();
set.add("foo");
set.add("foo");

// again only one element "foo"
set = new HashSet<>(Lists.of("foo", "foo"));

// crash, although it looks like a shortcut for the familiar behavior above
set = Set.of("foo", "foo");

Intuitively I'd expect the method to create an immutable Set of the input parameters after applying the Set's 'magic'.

What was / may have been the reasoning behind this design choice?

McFarlane
  • 1,777
  • 2
  • 22
  • 39
  • It also forbids null, unlike a normal hashset. – khelwood Aug 22 '18 at 09:19
  • `Set` forbids duplicates by definitions. – Arnaud Denoyelle Aug 22 '18 at 09:22
  • @ArnaudDenoyelle Yeah but sets normally ignore duplicates if you try and add them. They don't have to throw an exception. – khelwood Aug 22 '18 at 09:24
  • 1
    The reasoning is fully explained in [Kayaman's answer](https://stackoverflow.com/a/47629703/1898563). Because `Set.of` is designed for declaring sets manually, it is clearly a programmer error if the same item appears more than once. If something is clearly a programmer error, the best thing is to throw an exception as soon as possible so that they can fix it. – Michael Aug 22 '18 at 09:42

1 Answers1

4

Well first of all it clearly says it in the documentation:

They reject duplicate elements at creation time. Duplicate elements passed to a static factory method result in IllegalArgumentException.

I think it has something to do with the inner implementation of that Set.of. A major difference between set.of and a HashSet is that Set.of gives you an immutable set. No more elements can be added or removed. It's just to statically define a set if you need one (I see it more like utility method) and my guess is that it has simpler implementation that doesn't have the goal to remove duplicates for you.

Also a set doesn't have to allow you to add any element. For example HashSet might allow you but MyCustomSet might not. From the documentation of the add method of the Set interface:

Adds the specified element to this set if it is not already present (optional operation). More formally, adds the specified element e to this set if the set contains no element e2 such that Objects.equals(e, e2). If this set already contains the element, the call leaves the set unchanged and returns false. In combination with the restriction on constructors, this ensures that sets never contain duplicate elements.

> The stipulation above does not imply that sets must accept all elements; sets may refuse to add any particular element, including null, and throw an exception, as described in the specification for Collection.add. Individual set implementations should clearly document any restrictions on the elements that they may contain.

So how to handle duplicate elements and when to throw exception is up to the implementation

Veselin Davidov
  • 7,031
  • 1
  • 15
  • 23