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