Set.of(E... elements) - which Set implementation is it using? and what is its relation to new HashSet<>()?

collections, hashset, java, set

Solution

Don’t know, don’t care

The concrete class used by `Set.of` (and `List.of`, `Map.of`) is not documented. All we know is that the object returned (a) implements the interface, and (b) is unmodifiable.

That is all we need to know. We should not care about the particular concrete class used under the covers.

Being of unknown concrete class gives freedom to the implementors of the `of` methods.

- Those programmers are free to optimize according to the nature of your arguments. For example, if you are passing enum arguments, the highly optimized `EnumSet` class might be used behind the scenes.

- Those programmers are free to change their concrete class between versions of Java. For example, Java 17 implementation might return one concrete class while Java 18 returns another.

So you should never depend on a particular concrete class being utilized by the `of`/`copyOf` methods.

You asked:

What is the real difference between those two?

In your first one, we know the concrete class. And the resulting set is modifiable.

In your second one, we do not know the concrete class, nor do we care about the concrete class. And the resulting set is unmodifiable.

Code Concrete Class Modifiable

new HashSet<>() {{ add("a"); add("b"); add("c"); }} known modifiable

Set.of( "a", "b", "c" unknown unmodifiable

Avoid double-brace

As others said, it’s generally best to avoid double-brace initialization.

If you want the convenience of compact literals-style initialization of your modifiable collection, combine with the `of` methods. You can pass an existing collection to the constructor.

Set< String > set =
    new HashSet<>(
        Set.of( "a", "b", "c" )  // Pass a collection to constructor. 
    )
;

“But I do care …”

If you do care about the specific details of the implementation, then you should not use `Set.of`. The implementation details may vary as discussed above, so you should not rely on a specific implementation with `Set.of`.

When your project has specific needs, you should explicitly choose a particular implementation that meets those needs. You can choose one of the bundled implementations, obtain one from a third-party library such as Eclipse Collections or Google Guava, or write your own.

Tip: You can leverage the convenient syntax of `Set.of` by passing its result to the constructor of your chosen implementation. See the code example above:

new HashSet<>( Set.of( … ) )

Problem

I wanted to ask - what is the difference between ``` Set<CurrencyType> set1 = new HashSet<>() {{ add("a"); add("b"); add("c"); }} ``` and ``` Set<CurrencyType> set2 = Set.of( "a", "b", "c" ) ``` In debug mode in a @Test named `MySillyTest` (this name will come back very soon) i can see that `set1` is an instance of `MySillyTest$1`, but I assume it is just a `HashSet`. `set2` on the other hand is an instance of `ImmutableCollections$SetN`. What is the real difference between those two? What implementation of `java.util.Set` is `Set.of()` using? Is there a performance/memory usage/cpu usage difference between those two?

Original source

Related problems