Both Collector.of() are not correctly typed
Remi Forax
forax at univ-mlv.fr
Sun Nov 25 20:10:35 UTC 2018
ping !
Rémi
----- Mail original -----
> De: "Remi Forax" <forax at univ-mlv.fr>
> À: "core-libs-dev" <core-libs-dev at openjdk.java.net>
> Envoyé: Mardi 13 Novembre 2018 15:47:54
> Objet: Both Collector.of() are not correctly typed
> Last year,
> a student of mine as remarked that the two variants of Collector.of() are not
> correctly typed (the wildcards are missing)
> and obviously, this year it's one of my teaching assistant that has found
> exactly the same issue.
> So let's fix this issue.
>
> Adding the wildcards is both source and binary backward compatible in this case
> - the methods of are static (so no overriding possible)
> - the wildcards types are super types of the types of current version, so it
> will not break at use sites and
> - the erased signature is the same so it's a binary backward compatible change.
>
> The right code is
> @SuppressWarnings("unchecked")
> public static<T, R> Collector<T, R, R> of(Supplier<? extends R> supplier,
> BiConsumer<? super R, ? super T> accumulator,
> BinaryOperator<R> combiner,
> Characteristics... characteristics) {
> Objects.requireNonNull(supplier);
> Objects.requireNonNull(accumulator);
> Objects.requireNonNull(combiner);
> Objects.requireNonNull(characteristics);
> Set<Characteristics> cs = (characteristics.length == 0)
> ? Collectors.CH_ID
> :
> Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
> characteristics));
> return new Collectors.CollectorImpl<>((Supplier<R>)supplier, (BiConsumer<R,
> T>)accumulator, combiner, cs);
> }
> and
> @SuppressWarnings("unchecked")
> public static<T, A, R> Collector<T, A, R> of(Supplier<? extends A> supplier,
> BiConsumer<? super A, ? super T> accumulator,
> BinaryOperator<A> combiner,
> Function<? super A, ? extends R> finisher,
> Characteristics... characteristics) {
> Objects.requireNonNull(supplier);
> Objects.requireNonNull(accumulator);
> Objects.requireNonNull(combiner);
> Objects.requireNonNull(finisher);
> Objects.requireNonNull(characteristics);
> Set<Characteristics> cs = Collectors.CH_NOID;
> if (characteristics.length > 0) {
> cs = EnumSet.noneOf(Characteristics.class);
> Collections.addAll(cs, characteristics);
> cs = Collections.unmodifiableSet(cs);
> }
> return new Collectors.CollectorImpl<>((Supplier<R>)supplier, (BiConsumer<R,
> T>)accumulator, combiner, (Function<A, R>)finisher, cs);
> }
>
> You may ask why the code is safe given there are now some
> @SuppressWarnings("unchecked"), it's because for a functional interface,
> the parameter types are contra-variant and the return type is covariant.
>
> At one point in the future, perhaps JEP 300 [1] will be implemented, in that
> case we will be able to remove the @SuppressWarnings.
>
> You may also notice that, we may want at the same time replace the
> unmodifiableSet(EnumSet.of() + add) with Set.of(),
> i've not done that change given it's not related to the typing issue.
>
> cheers,
> Rémi
>
> [1] https://openjdk.java.net/jeps/300
More information about the core-libs-dev
mailing list