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