Why does Set.of disallow duplicate elements?

forax at univ-mlv.fr forax at univ-mlv.fr
Sun Jan 31 21:35:24 UTC 2021






De: "dfranken jdk" <dfranken.jdk at gmail.com> 
À: "Remi Forax" <forax at univ-mlv.fr> 
Cc: "core-libs-dev" <core-libs-dev at openjdk.java.net> 
Envoyé: Dimanche 31 Janvier 2021 13:54:44 
Objet: Re: Why does Set.of disallow duplicate elements? 




BQ_BEGIN

Okay, I understand this reasoning, but when you want to construct a Set from an array, you might be tempted to use Set.of(...) because it looks like it supports an array and indeed, you can do Set.of(new int[] {1, 2 }) I believe? 

BQ_END

Set.of(int[]) will call Set.of(E) with E being an int[]. 
but 
Set.of(new Integer[] { ... }) calls Set.of(...). 


BQ_BEGIN


Maybe this is just a quirk because of how varargs work. 

BQ_END

Yes, exactly, it's a known issue with varargs, you have no way to say, i don't want this varargs to be called with an array. 


BQ_BEGIN


I wondered if there was a canonical way to create a Set from an array, but couldn't find it, maybe I am missing something? 
I did notice Arrays.asList exists (which makes sense because it creates an ArrayList backed by the array), but not Arrays.asSet. 

BQ_END

asList() reuse the same backing array, you can not do that with asSet() or contains() will be in O(n) in the worst case. 


BQ_BEGIN


So the way I would create a Set from an array would be either Arrays.stream(myArr).collect(Collectors.toUnmodifiableSet()) or new HashSet<>(Arrays.asList(myArray)) or Set.copyOf(Arrays.asList(myArray)). 

BQ_END

yes, the last one is the easy way to create an unmodifiable set from an array. 


BQ_BEGIN


I'm not saying the way it is currently implemented is wrong, it's just something which can suprise developers as it surprised me. :) 

BQ_END

Arrays are currently second class citizen in Java, because they are always modifiable and always covariant (String[] can be seen as a Object[]). 
We have talked several times to introduce new variants of arrays, non-modifiable one, non-covariant one, etc under the name Array 2.0, but Valhalla generics is a blocker for that project. 
Once Valhalla is done, it may be a follow up. 


BQ_BEGIN


Kind regards, 

Dave 

BQ_END


regards, 
Rémi 


BQ_BEGIN



Op za 30 jan. 2021 om 21:30 schreef Remi Forax < [ mailto:forax at univ-mlv.fr | forax at univ-mlv.fr ] >: 

BQ_BEGIN
Set.of() is the closest way we've got to a literal Set without having introduced a special syntax for that in the language. 

The idea is that if you conceptually want to write 
Set<String> set = { "hello", "world" }; 
instead, you write 
Set<String> set = Set.of("hello", "world"); 

In that context, it makes sense to reject Set constructed with the same element twice because this is usually a programming error. 
So 
Set.of("hello", "hello") 
throws an IAE. 

If you want a Set from a collection of elements, you can use 
Set.copyOf(List.of("hello", "hello")) 

regards, 
Rémi 

----- Mail original ----- 
> De: "dfranken jdk" < [ mailto:dfranken.jdk at gmail.com | dfranken.jdk at gmail.com ] > 
> À: "core-libs-dev" < [ mailto:core-libs-dev at openjdk.java.net | core-libs-dev at openjdk.java.net ] > 
> Envoyé: Samedi 30 Janvier 2021 19:30:06 
> Objet: Why does Set.of disallow duplicate elements? 

> Dear users, 
> 
> While looking at the implementation of Set.of(...) I noticed that 
> duplicate elements are not allowed, e.g. Set.of(1, 1) will throw an 
> IllegalArgumentException. Why has it been decided to do this? 
> 
> My expectation was that duplicates would simply be removed. 
> 
> If I do for instance new HashSet<>(<collection containing duplicates>) 
> it works and duplicates are removed. To me, it looks a bit inconsistent 
> to have duplicates removed for a collection passed in the constructor, 
> but not for a collection (even though it is a vararg array) passed to a 
> static factory method. 
> 
> Kind regards, 
> 
> Dave Franken 

BQ_END


BQ_END




More information about the core-libs-dev mailing list