Home > Back-end >  Why in Collectors.java Class it is possible to use array indexing?
Why in Collectors.java Class it is possible to use array indexing?

Time:01-09

In collectors.java class I found this method. I cannot explain myself why you can use array indexing here. I mean this line (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },

public static <T, U> Collector<T, ?, U> reducing(U identity,
                                Function<? super T, ? extends U> mapper,
                                BinaryOperator<U> op) {
        return new CollectorImpl<>(
                boxSupplier(identity),
                (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
                a -> a[0], CH_NOID);
    }

CodePudding user response:

Why is it possible to use an array subscript here? Because it's an array, why wouldn't you be able to use it just like any other array?

The Collectors#reducing method returns a new Collector instance:

    return new CollectorImpl<>(
            boxSupplier(identity),
            (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
            (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
            a -> a[0],
            CH_NOID);

The signature of this CollectorImpl constructor is:

    CollectorImpl(Supplier<A> supplier,
                  BiConsumer<A, T> accumulator,
                  BinaryOperator<A> combiner,
                  Function<A,R> finisher,
                  Set<Characteristics> characteristics) {

The signature of boxSupplier is:

private static <T> Supplier<T[]> boxSupplier(T identity) {
    return () -> (T[]) new Object[] { identity };
}

which returns a Supplier which supplies an array (effectively wrapping the specified identity object lazily in an array with a single element). Consequently, type param A of CollectorImpl has to be an array of the identity's type, meaning that the second and third parameter are a BiConsumer of an array and a BinaryOperator on an array. The formal parameter a in the lambda's parameter list therefore is of an array type. Since it's an array, it can be used like any other array.

This is called type inference:

Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable. The inference algorithm determines the types of the arguments and, if available, the type that the result is being assigned, or returned. Finally, the inference algorithm tries to find the most specific type that works with all of the arguments.

You could specify the lambda parameter types explicitly to make it clearer:

public static <T, U>
Collector<T, ?, U> reducing(U identity,
                            Function<? super T, ? extends U> mapper,
                            BinaryOperator<U> op) {
    return new CollectorImpl<>(
            boxSupplier(identity),
            (U[] a, T t) -> {a[0] = op.apply(a[0], mapper.apply(t));},
            (U[] a, U[] b) -> {a[0] = op.apply(a[0], b[0]);return a;},
            (U[] a) -> a[0],
            CH_NOID);
}

Or you could replace each lambda expression with an anonymous class:

    return new CollectorImpl<>(
            new Supplier<U[]>() {
                @Override
                public U[] get() {
                    return (U[]) new Object[]{identity};
                }
            },
            new BiConsumer<U[], T>() {
                @Override
                public void accept(final U[] a, final T t) {
                    a[0] = op.apply(a[0], mapper.apply(t));
                }
            },
            new BinaryOperator<U[]>() {
                @Override
                public U[] apply(final U[] a, final U[] b) {
                    a[0] = op.apply(a[0], b[0]);
                    return a;
                }
            },
            new Function<U[], U>() {
                @Override
                public U apply(final U[] a) {
                    return a[0];
                }
            },
            CH_NOID);
  • Related