All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.stream.Collectors Maven / Gradle / Ivy

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

The newest version!
/*
 * Copyright (C) 2016, 2017, 2018, 2019 HaiYang Li
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.landawn.abacus.util.stream;

import static com.landawn.abacus.util.stream.StreamBase.ERROR_MSG_FOR_NO_SUCH_EX;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Deque;
import java.util.DoubleSummaryStatistics;
import java.util.EnumSet;
import java.util.IntSummaryStatistics;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Collector;
import java.util.stream.Collector.Characteristics;

import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.exception.TooManyElementsException;
import com.landawn.abacus.util.Array;
import com.landawn.abacus.util.BiMap;
import com.landawn.abacus.util.BigDecimalSummaryStatistics;
import com.landawn.abacus.util.BigIntegerSummaryStatistics;
import com.landawn.abacus.util.BooleanList;
import com.landawn.abacus.util.ByteList;
import com.landawn.abacus.util.ByteSummaryStatistics;
import com.landawn.abacus.util.CharList;
import com.landawn.abacus.util.CharSummaryStatistics;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.Comparators;
import com.landawn.abacus.util.DataSet;
import com.landawn.abacus.util.DoubleList;
import com.landawn.abacus.util.FloatList;
import com.landawn.abacus.util.FloatSummaryStatistics;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.Fn.BiConsumers;
import com.landawn.abacus.util.Fn.BinaryOperators;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.Holder;
import com.landawn.abacus.util.ImmutableList;
import com.landawn.abacus.util.ImmutableMap;
import com.landawn.abacus.util.ImmutableSet;
import com.landawn.abacus.util.IntList;
import com.landawn.abacus.util.Joiner;
import com.landawn.abacus.util.KahanSummation;
import com.landawn.abacus.util.ListMultimap;
import com.landawn.abacus.util.LongList;
import com.landawn.abacus.util.Multimap;
import com.landawn.abacus.util.Multiset;
import com.landawn.abacus.util.MutableBoolean;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.ObjIterator;
import com.landawn.abacus.util.Pair;
import com.landawn.abacus.util.ShortList;
import com.landawn.abacus.util.ShortSummaryStatistics;
import com.landawn.abacus.util.Strings;
import com.landawn.abacus.util.Tuple;
import com.landawn.abacus.util.Tuple.Tuple2;
import com.landawn.abacus.util.Tuple.Tuple3;
import com.landawn.abacus.util.Tuple.Tuple4;
import com.landawn.abacus.util.Tuple.Tuple5;
import com.landawn.abacus.util.Tuple.Tuple6;
import com.landawn.abacus.util.Tuple.Tuple7;
import com.landawn.abacus.util.cs;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.function.QuadFunction;
import com.landawn.abacus.util.function.ToByteFunction;
import com.landawn.abacus.util.function.ToCharFunction;
import com.landawn.abacus.util.function.ToFloatFunction;
import com.landawn.abacus.util.function.ToShortFunction;
import com.landawn.abacus.util.function.TriFunction;

/**
 * Factory utility class for {@code Collector}.
 *
 * @see {@code java.util.stream.Collector}
 * @see {@code java.util.stream.Collectors}
 */
@SuppressWarnings({ "java:S1694" })
public abstract sealed class Collectors permits Collectors.MoreCollectors { // NOSONAR

    static final Object NONE = ClassUtil.createNullMask(); //NOSONAR

    static final Characteristics[] CH_NOID = {};

    static final Characteristics[] CH_ID = { Characteristics.IDENTITY_FINISH };

    static final Characteristics[] CH_UNORDERED_NOID = { Characteristics.UNORDERED };

    static final Characteristics[] CH_UNORDERED_ID = { Characteristics.UNORDERED, Characteristics.IDENTITY_FINISH };

    /**
     * @deprecated This class is not intended to be used.
     */
    @Deprecated
    static final Characteristics[] CH_CONCURRENT_NOID = { Characteristics.CONCURRENT, Characteristics.UNORDERED };

    /**
     * @deprecated This class is not intended to be used.
     */
    @Deprecated
    static final Characteristics[] CH_CONCURRENT_ID = { Characteristics.CONCURRENT, Characteristics.UNORDERED, Characteristics.IDENTITY_FINISH };

    // ============================================================================================================

    static final Function, ImmutableList> ImmutableList_Finisher = ImmutableList::wrap;

    static final Function, ImmutableSet> ImmutableSet_Finisher = ImmutableSet::wrap;

    static final Function, ImmutableMap> ImmutableMap_Finisher = ImmutableMap::wrap;

    static final BiConsumer, Object> Multiset_Accumulator = Multiset::add;

    static final BinaryOperator> Multiset_Combiner = (a, b) -> {
        a.addAll(b);
        return a;
    };

    static final BiConsumer BooleanList_Accumulator = BooleanList::add;

    static final BinaryOperator BooleanList_Combiner = (a, b) -> {
        a.addAll(b);
        return a;
    };

    static final Function BooleanArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer CharList_Accumulator = CharList::add;

    static final BinaryOperator CharList_Combiner = (a, b) -> {
        a.addAll(b);
        return a;
    };

    static final Function CharArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer ByteList_Accumulator = ByteList::add;

    static final BinaryOperator ByteList_Combiner = (a, b) -> {
        if (a.size() >= b.size()) {
            a.addAll(b);
            return a;
        } else {
            b.addAll(a);
            return b;
        }
    };

    static final Function ByteArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer ShortList_Accumulator = ShortList::add;

    static final BinaryOperator ShortList_Combiner = (a, b) -> {
        if (a.size() >= b.size()) {
            a.addAll(b);
            return a;
        } else {
            b.addAll(a);
            return b;
        }
    };

    static final Function ShortArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer IntList_Accumulator = IntList::add;

    static final BinaryOperator IntList_Combiner = (a, b) -> {
        if (a.size() >= b.size()) {
            a.addAll(b);
            return a;
        } else {
            b.addAll(a);
            return b;
        }
    };

    static final Function IntArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer LongList_Accumulator = LongList::add;

    static final BinaryOperator LongList_Combiner = (a, b) -> {
        if (a.size() >= b.size()) {
            a.addAll(b);
            return a;
        } else {
            b.addAll(a);
            return b;
        }
    };

    static final Function LongArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer FloatList_Accumulator = FloatList::add;

    static final BinaryOperator FloatList_Combiner = (a, b) -> {
        if (a.size() >= b.size()) {
            a.addAll(b);
            return a;
        } else {
            b.addAll(a);
            return b;
        }
    };

    static final Function FloatArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer DoubleList_Accumulator = DoubleList::add;

    static final BinaryOperator DoubleList_Combiner = (a, b) -> {
        if (a.size() >= b.size()) {
            a.addAll(b);
            return a;
        } else {
            b.addAll(a);
            return b;
        }
    };

    static final Function DoubleArray_Finisher = t -> t.trimToSize().array();

    static final BiConsumer Joiner_Accumulator = Joiner::append;

    static final BinaryOperator Joiner_Combiner = (a, b) -> {
        if (a.length() > b.length()) {
            a.merge(b);
            b.close();
            return a;
        } else {
            b.merge(a);
            a.close();
            return b;
        }
    };

    static final Function Joiner_Finisher = Joiner::toString;

    static final Supplier SummingInt_Supplier = () -> new int[1];
    static final Supplier SummingInt_Supplier_2 = () -> new int[2];
    static final Supplier SummingInt_Supplier_3 = () -> new int[3];

    static final Supplier SummingIntToLong_Supplier = () -> new long[1];
    static final Supplier SummingIntToLong_Supplier_2 = () -> new long[2];
    static final Supplier SummingIntToLong_Supplier_3 = () -> new long[3];

    static final BinaryOperator SummingInt_Combiner = (a, b) -> {
        a[0] += b[0];
        return a;
    };

    static final BinaryOperator SummingInt_Combiner_2 = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        return a;
    };

    static final BinaryOperator SummingInt_Combiner_3 = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        a[2] += b[2];
        return a;
    };

    static final BinaryOperator SummingIntToLong_Combiner = (a, b) -> {
        a[0] += b[0];
        return a;
    };

    static final BinaryOperator SummingIntToLong_Combiner_2 = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        return a;
    };

    static final BinaryOperator SummingIntToLong_Combiner_3 = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        a[2] += b[2];
        return a;
    };

    static final Function SummingInt_Finisher = a -> a[0];
    static final Function> SummingInt_Finisher_2 = a -> Tuple.of(a[0], a[1]);
    static final Function> SummingInt_Finisher_3 = a -> Tuple.of(a[0], a[1], a[2]);

    static final Function SummingIntToLong_Finisher = a -> a[0];
    static final Function> SummingIntToLong_Finisher_2 = a -> Tuple.of(a[0], a[1]);
    static final Function> SummingIntToLong_Finisher_3 = a -> Tuple.of(a[0], a[1], a[2]);

    static final Supplier SummingLong_Supplier = () -> new long[1];
    static final Supplier SummingLong_Supplier_2 = () -> new long[2];
    static final Supplier SummingLong_Supplier_3 = () -> new long[3];

    static final BinaryOperator SummingLong_Combiner = (a, b) -> {
        a[0] += b[0];
        return a;
    };

    static final BinaryOperator SummingLong_Combiner_2 = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        return a;
    };

    static final BinaryOperator SummingLong_Combiner_3 = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        a[2] += b[2];
        return a;
    };

    static final Function SummingLong_Finisher = a -> a[0];
    static final Function> SummingLong_Finisher_2 = a -> Tuple.of(a[0], a[1]);
    static final Function> SummingLong_Finisher_3 = a -> Tuple.of(a[0], a[1], a[2]);

    static final Supplier SummingDouble_Supplier = KahanSummation::new;
    static final Supplier SummingDouble_Supplier_2 = () -> new KahanSummation[] { new KahanSummation(), new KahanSummation() };
    static final Supplier SummingDouble_Supplier_3 = () -> new KahanSummation[] { new KahanSummation(), new KahanSummation(),
            new KahanSummation() };

    static final BinaryOperator SummingDouble_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final BinaryOperator SummingDouble_Combiner_2 = (a, b) -> {
        a[0].combine(b[0]);
        a[1].combine(b[1]);
        return a;
    };

    static final BinaryOperator SummingDouble_Combiner_3 = (a, b) -> {
        a[0].combine(b[0]);
        a[1].combine(b[1]);
        a[2].combine(b[2]);
        return a;
    };

    static final Function SummingDouble_Finisher = KahanSummation::sum;
    static final Function> SummingDouble_Finisher_2 = a -> Tuple.of(a[0].sum(), a[1].sum());
    static final Function> SummingDouble_Finisher_3 = a -> Tuple.of(a[0].sum(), a[1].sum(), a[2].sum());

    static final Supplier SummingBigInteger_Supplier = () -> new BigInteger[] { BigInteger.ZERO };
    static final Supplier SummingBigInteger_Supplier_2 = () -> new BigInteger[] { BigInteger.ZERO, BigInteger.ZERO };
    static final Supplier SummingBigInteger_Supplier_3 = () -> new BigInteger[] { BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO };

    static final BinaryOperator SummingBigInteger_Combiner = (a, b) -> {
        a[0] = a[0].add(b[0]);
        return a;
    };

    static final BinaryOperator SummingBigInteger_Combiner_2 = (a, b) -> {
        a[0] = a[0].add(b[0]);
        a[1] = a[1].add(b[1]);
        return a;
    };

    static final BinaryOperator SummingBigInteger_Combiner_3 = (a, b) -> {
        a[0] = a[0].add(b[0]);
        a[1] = a[1].add(b[1]);
        a[2] = a[2].add(b[2]);
        return a;
    };

    static final Function SummingBigInteger_Finisher = a -> a[0];
    static final Function> SummingBigInteger_Finisher_2 = a -> Tuple.of(a[0], a[1]);
    static final Function> SummingBigInteger_Finisher_3 = a -> Tuple.of(a[0], a[1], a[2]);

    static final Supplier SummingBigDecimal_Supplier = () -> new BigDecimal[] { BigDecimal.ZERO };
    static final Supplier SummingBigDecimal_Supplier_2 = () -> new BigDecimal[] { BigDecimal.ZERO, BigDecimal.ZERO };
    static final Supplier SummingBigDecimal_Supplier_3 = () -> new BigDecimal[] { BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO };

    static final BinaryOperator SummingBigDecimal_Combiner = (a, b) -> {
        a[0] = a[0].add(b[0]);
        return a;
    };

    static final BinaryOperator SummingBigDecimal_Combiner_2 = (a, b) -> {
        a[0] = a[0].add(b[0]);
        a[1] = a[1].add(b[1]);
        return a;
    };

    static final BinaryOperator SummingBigDecimal_Combiner_3 = (a, b) -> {
        a[0] = a[0].add(b[0]);
        a[1] = a[1].add(b[1]);
        a[2] = a[2].add(b[2]);
        return a;
    };

    static final Function SummingBigDecimal_Finisher = a -> a[0];
    static final Function> SummingBigDecimal_Finisher_2 = a -> Tuple.of(a[0], a[1]);
    static final Function> SummingBigDecimal_Finisher_3 = a -> Tuple.of(a[0], a[1], a[2]);

    static final Supplier AveragingInt_Supplier = () -> new long[2];
    static final Supplier> AveragingInt_Supplier_2 = () -> Pair.of(new long[2], new long[2]);
    static final Supplier> AveragingInt_Supplier_3 = () -> Pair.of(new long[3], new long[3]);

    static final BinaryOperator AveragingInt_Combiner = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        return a;
    };

    static final BinaryOperator> AveragingInt_Combiner_2 = (a, b) -> {
        a.left[0] += b.left[0];
        a.left[1] += b.left[1];
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        return a;
    };

    static final BinaryOperator> AveragingInt_Combiner_3 = (a, b) -> {
        a.left[0] += b.left[0];
        a.left[1] += b.left[1];
        a.left[2] += b.left[2];
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        a.right[2] += b.right[2];
        return a;
    };

    static final Function AveragingInt_Finisher = a -> {
        if (a[1] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return ((double) a[0]) / a[1];
    };

    static final Function AveragingInt_Finisher_op = a -> {
        if (a[1] == 0) {
            return OptionalDouble.empty();
        } else {
            return OptionalDouble.of(((double) a[0]) / a[1]);
        }
    };

    static final Function, Tuple2> AveragingInt_Finisher_2 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple2.of(((double) a.left[0]) / a.right[0], ((double) a.left[1]) / a.right[1]);
    };

    static final Function, Tuple3> AveragingInt_Finisher_3 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0 || a.right[2] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple2.of(((double) a.left[0]) / a.right[0], ((double) a.left[1]) / a.right[1], ((double) a.left[2]) / a.right[2]);
    };

    static final Supplier AveragingLong_Supplier = () -> new long[2];
    static final Supplier> AveragingLong_Supplier_2 = () -> Pair.of(new long[2], new long[2]);
    static final Supplier> AveragingLong_Supplier_3 = () -> Pair.of(new long[3], new long[3]);

    static final BinaryOperator AveragingLong_Combiner = (a, b) -> {
        a[0] += b[0];
        a[1] += b[1];
        return a;
    };

    static final BinaryOperator> AveragingLong_Combiner_2 = (a, b) -> {
        a.left[0] += b.left[0];
        a.left[1] += b.left[1];
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        return a;
    };

    static final BinaryOperator> AveragingLong_Combiner_3 = (a, b) -> {
        a.left[0] += b.left[0];
        a.left[1] += b.left[1];
        a.left[2] += b.left[2];
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        a.right[2] += b.right[2];
        return a;
    };

    static final Function AveragingLong_Finisher = a -> {
        if (a[1] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return ((double) a[0]) / a[1];
    };

    static final Function AveragingLong_Finisher_op = a -> {
        if (a[1] == 0) {
            return OptionalDouble.empty();
        } else {
            return OptionalDouble.of(((double) a[0]) / a[1]);
        }
    };

    static final Function, Tuple2> AveragingLong_Finisher_2 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple2.of(((double) a.left[0]) / a.right[0], ((double) a.left[1]) / a.right[1]);
    };

    static final Function, Tuple3> AveragingLong_Finisher_3 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0 || a.right[2] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple2.of(((double) a.left[0]) / a.right[0], ((double) a.left[1]) / a.right[1], ((double) a.left[2]) / a.right[2]);
    };

    static final Supplier AveragingDouble_Supplier = KahanSummation::new;
    static final Supplier AveragingDouble_Supplier_2 = () -> new KahanSummation[] { new KahanSummation(), new KahanSummation() };
    static final Supplier AveragingDouble_Supplier_3 = () -> new KahanSummation[] { new KahanSummation(), new KahanSummation(),
            new KahanSummation() };

    static final BinaryOperator AveragingDouble_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final BinaryOperator AveragingDouble_Combiner_2 = (a, b) -> {
        a[0].combine(b[0]);
        a[1].combine(b[1]);
        return a;
    };

    static final BinaryOperator AveragingDouble_Combiner_3 = (a, b) -> {
        a[0].combine(b[0]);
        a[1].combine(b[1]);
        a[2].combine(b[2]);
        return a;
    };

    static final Function AveragingDouble_Finisher = a -> {
        if (a.count() == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return a.average().get();
    };

    static final Function AveragingDouble_Finisher_op = KahanSummation::average;

    static final Function> AveragingDouble_Finisher_2 = a -> {
        if (a[0].count() == 0 || a[1].count() == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple.of(a[0].average().get(), a[1].average().get());
    };

    static final Function> AveragingDouble_Finisher_3 = a -> {
        if (a[0].count() == 0 || a[1].count() == 0 || a[2].count() == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple.of(a[0].average().get(), a[1].average().get(), a[2].average().get());
    };

    static final Supplier> AveragingBigInteger_Supplier = () -> Pair.of(BigInteger.ZERO, new long[1]);

    static final Supplier> AveragingBigInteger_Supplier_2 = () -> Pair.of(new BigInteger[] { BigInteger.ZERO, BigInteger.ZERO },
            new long[2]);

    static final Supplier> AveragingBigInteger_Supplier_3 = () -> Pair
            .of(new BigInteger[] { BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO }, new long[3]);

    static final BinaryOperator> AveragingBigInteger_Combiner = (a, b) -> {
        a.setLeft(a.left.add(b.left));
        a.right[0] += b.right[0];
        return a;
    };

    static final BinaryOperator> AveragingBigInteger_Combiner_2 = (a, b) -> {
        a.left[0] = a.left[0].add(b.left[0]);
        a.left[1] = a.left[1].add(b.left[1]);
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        return a;
    };

    static final BinaryOperator> AveragingBigInteger_Combiner_3 = (a, b) -> {
        a.left[0] = a.left[0].add(b.left[0]);
        a.left[1] = a.left[1].add(b.left[1]);
        a.left[2] = a.left[2].add(b.left[2]);
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        a.right[2] += b.right[2];
        return a;
    };

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, BigDecimal> AveragingBigInteger_Finisher = a -> {
        if (a.right[0] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return new BigDecimal(a.left).divide(new BigDecimal(a.right[0]));
    };

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, Optional> AveragingBigInteger_Finisher_op = a -> a.right[0] == 0 ? Optional.empty()
            : Optional.of(new BigDecimal(a.left).divide(new BigDecimal(a.right[0])));

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, Tuple2> AveragingBigInteger_Finisher_2 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple.of(new BigDecimal(a.left[0]).divide(new BigDecimal(a.right[0])), new BigDecimal(a.left[1]).divide(new BigDecimal(a.right[1])));
    };

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, Tuple3> AveragingBigInteger_Finisher_3 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0 || a.right[2] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple.of(new BigDecimal(a.left[0]).divide(new BigDecimal(a.right[0])), new BigDecimal(a.left[1]).divide(new BigDecimal(a.right[1])),
                new BigDecimal(a.left[2]).divide(new BigDecimal(a.right[2])));
    };

    static final Supplier> AveragingBigDecimal_Supplier = () -> Pair.of(BigDecimal.ZERO, new long[1]);

    static final Supplier> AveragingBigDecimal_Supplier_2 = () -> Pair.of(new BigDecimal[] { BigDecimal.ZERO, BigDecimal.ZERO },
            new long[2]);

    static final Supplier> AveragingBigDecimal_Supplier_3 = () -> Pair
            .of(new BigDecimal[] { BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO }, new long[3]);

    static final BinaryOperator> AveragingBigDecimal_Combiner = (a, b) -> {
        a.setLeft(a.left.add(b.left));
        a.right[0] += b.right[0];
        return a;
    };

    static final BinaryOperator> AveragingBigDecimal_Combiner_2 = (a, b) -> {
        a.left[0] = a.left[0].add(b.left[0]);
        a.left[1] = a.left[1].add(b.left[1]);
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        return a;
    };

    static final BinaryOperator> AveragingBigDecimal_Combiner_3 = (a, b) -> {
        a.left[0] = a.left[0].add(b.left[0]);
        a.left[1] = a.left[1].add(b.left[1]);
        a.left[2] = a.left[2].add(b.left[2]);
        a.right[0] += b.right[0];
        a.right[1] += b.right[1];
        a.right[2] += b.right[2];
        return a;
    };

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, BigDecimal> AveragingBigDecimal_Finisher = a -> {
        if (a.right[0] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return a.left.divide(new BigDecimal(a.right[0]));
    };

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, Optional> AveragingBigDecimal_Finisher_op = a -> a.right[0] == 0 ? Optional.empty()
            : Optional.of(a.left.divide(new BigDecimal(a.right[0])));

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, Tuple2> AveragingBigDecimal_Finisher_2 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple.of(a.left[0].divide(new BigDecimal(a.right[0])), a.left[1].divide(new BigDecimal(a.right[1])));
    };

    @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
    static final Function, Tuple3> AveragingBigDecimal_Finisher_3 = a -> {
        if (a.right[0] == 0 || a.right[1] == 0 || a.right[2] == 0) {
            throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX);
        }

        return Tuple.of(a.left[0].divide(new BigDecimal(a.right[0])), a.left[1].divide(new BigDecimal(a.right[1])),
                a.left[2].divide(new BigDecimal(a.right[2])));
    };

    static final Supplier SummarizingChar_Supplier = CharSummaryStatistics::new;

    static final BinaryOperator SummarizingChar_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingByte_Supplier = ByteSummaryStatistics::new;

    static final BinaryOperator SummarizingByte_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingShort_Supplier = ShortSummaryStatistics::new;

    static final BinaryOperator SummarizingShort_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingInt_Supplier = IntSummaryStatistics::new;

    static final BinaryOperator SummarizingInt_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingLong_Supplier = LongSummaryStatistics::new;

    static final BinaryOperator SummarizingLong_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingFloat_Supplier = FloatSummaryStatistics::new;

    static final BinaryOperator SummarizingFloat_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingDouble_Supplier = DoubleSummaryStatistics::new;

    static final BinaryOperator SummarizingDouble_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingBigInteger_Supplier = BigIntegerSummaryStatistics::new;

    static final BinaryOperator SummarizingBigInteger_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Supplier SummarizingBigDecimal_Supplier = BigDecimalSummaryStatistics::new;

    static final BinaryOperator SummarizingBigDecimal_Combiner = (a, b) -> {
        a.combine(b);
        return a;
    };

    static final Function, Object> Reducing_Finisher_0 = Holder::value;

    static final BiConsumer, Object> Reducing_Accumulator = OptHolder::accept;

    static final BinaryOperator> Reducing_Combiner = (a, b) -> {
        if (b.present) {
            a.accept(b.value);
        }

        return a;
    };

    static final Function, Optional> Reducing_Finisher = a -> a.present ? Optional.of(a.value) : (Optional) Optional.empty();

    static final BiConsumer, Object> Reducing_Accumulator_2 = MappingOptHolder::accept;

    static final BinaryOperator> Reducing_Combiner_2 = (a, b) -> {
        if (b.present) {
            if (a.present) {
                a.value = a.op.apply(a.value, b.value);
            } else {
                a.value = b.value;
                a.present = true;
            }
        }

        return a;
    };

    static final Function, Optional> Reducing_Finisher_2 = a -> a.present ? Optional.of(a.value)
            : (Optional) Optional.empty();

    // ============================================================================================================

    Collectors() {
    }

    //    static class CollectorImpl implements Collector {
    //        private static final Function IDENTITY_FINISHER = t -> t;
    //
    //        private final Supplier supplier;
    //        private final BiConsumer accumulator;
    //        private final BinaryOperator combiner;
    //        private final Function finisher;
    //        private final Set characteristics;
    //
    //        CollectorImpl(final Supplier supplier, final BiConsumer accumulator, final BinaryOperator combiner,
    //                final Set characteristics) {
    //            this(supplier, accumulator, combiner, (Function) IDENTITY_FINISHER, characteristics);
    //        }
    //
    //        @SuppressWarnings("rawtypes")
    //        CollectorImpl(final Supplier supplier, final BiConsumer accumulator, final BinaryOperator combiner,
    //                final Function finisher, final Set characteristics) {
    //            this.supplier = (Supplier) supplier;
    //            this.accumulator = (BiConsumer) accumulator;
    //            this.combiner = combiner;
    //            this.finisher = (Function) finisher;
    //            this.characteristics = characteristics == null ? N.emptySet() : characteristics;
    //        }
    //
    //        @Override
    //        public BiConsumer accumulator() {
    //            return accumulator;
    //        }
    //
    //        @Override
    //        public Supplier supplier() {
    //            return supplier;
    //        }
    //
    //        @Override
    //        public BinaryOperator combiner() {
    //            return combiner;
    //        }
    //
    //        @Override
    //        public Function finisher() {
    //            return finisher;
    //        }
    //
    //        @Override
    //        public Set characteristics() {
    //            return characteristics;
    //        }
    //    }

    /**
     * Creates a new `Collector` with the specified supplier, accumulator, and combiner.
     *
     * @param  the type of input elements to the collector
     * @param  the type of the mutable result container and the final result
     * @param supplier the supplier function that provides a new mutable result container
     * @param accumulator the accumulator function that folds a value into a mutable result container
     * @param combiner the combiner function that merges two result containers
     * @param characteristics optional characteristics of the collector
     * @return a new `Collector` with the specified supplier, accumulator, and combiner
     * @see Collector#of(Supplier, BiConsumer, BinaryOperator, Characteristics...)
     */
    public static  Collector create(final Supplier supplier, final BiConsumer accumulator,
            final BinaryOperator combiner, final Characteristics... characteristics) {
        return Collector.of((Supplier) supplier, (BiConsumer) accumulator, combiner, characteristics);
    }

    /**
     * Creates a new `Collector` with the specified supplier, accumulator, and combiner.
     *
     * @param  the type of input elements to the collector
     * @param  the type of the mutable result container and the final result
     * @param supplier the supplier function that provides a new mutable result container
     * @param accumulator the accumulator function that folds a value into a mutable result container
     * @param combiner the combiner function that merges two result containers
     * @param characteristics optional characteristics of the collector
     * @return a new `Collector` with the specified supplier, accumulator, and combiner
     * @see Collector#of(Supplier, BiConsumer, BinaryOperator, Characteristics...)
     */
    public static  Collector create(final Supplier supplier, final BiConsumer accumulator,
            final BinaryOperator combiner, final Collection characteristics) {
        return Collector.of((Supplier) supplier, (BiConsumer) accumulator, combiner,
                N.isEmpty(characteristics) ? CH_NOID : characteristics.toArray(Characteristics[]::new));
    }

    /**
     * Creates a new `Collector` with the specified supplier, accumulator, combiner, and finisher.
     *
     * @param  the type of input elements to the collector
     * @param  the type of the intermediate accumulation result
     * @param  the type of the final result of the collector
     * @param supplier the supplier function that provides a new mutable result container
     * @param accumulator the accumulator function that folds a value into a mutable result container
     * @param combiner the combiner function that merges two result containers
     * @param finisher the function that transforms the intermediate result to the final result
     * @param characteristics optional characteristics of the collector
     * @return a new `Collector` with the specified components
     * @see Collector#of(Supplier, BiConsumer, BinaryOperator, Function, Characteristics...)
     */
    public static  Collector create(final Supplier supplier, final BiConsumer accumulator,
            final BinaryOperator combiner, final Function finisher, final Characteristics... characteristics) {
        return Collector.of((Supplier) supplier, (BiConsumer) accumulator, combiner, (Function) finisher, characteristics);
    }

    /**
     * Creates a new `Collector` with the specified supplier, accumulator, combiner, and finisher.
     *
     * @param  the type of input elements to the collector
     * @param  the type of the intermediate accumulation result
     * @param  the type of the final result of the collector
     * @param supplier the supplier function that provides a new mutable result container
     * @param accumulator the accumulator function that folds a value into a mutable result container
     * @param combiner the combiner function that merges two result containers
     * @param finisher the function that transforms the intermediate result to the final result
     * @param characteristics optional characteristics of the collector
     * @return a new `Collector` with the specified components
     * @see Collector#of(Supplier, BiConsumer, BinaryOperator, Function, Characteristics...)
     */
    public static  Collector create(final Supplier supplier, final BiConsumer accumulator,
            final BinaryOperator combiner, final Function finisher, final Collection characteristics) {
        return Collector.of((Supplier) supplier, (BiConsumer) accumulator, combiner, (Function) finisher,
                N.isEmpty(characteristics) ? CH_NOID : characteristics.toArray(Characteristics[]::new));
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toList() {
        final Supplier> supplier = Suppliers.ofList();

        return toCollection(supplier);
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toLinkedList() {
        final Supplier> supplier = Suppliers.ofLinkedList();

        return toCollection(supplier);
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toImmutableList() {
        final Collector> downstream = toList();
        @SuppressWarnings("rawtypes")
        final Function, ImmutableList> finisher = (Function) ImmutableList_Finisher;

        return collectingAndThen(downstream, finisher);
    }

    /**
     *
     * @param 
     * @return
     * @see java.util.stream.Collectors#toUnmodifiableList
     */
    public static  Collector> toUnmodifiableList() {
        return java.util.stream.Collectors.toUnmodifiableList();
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toSet() {
        final Supplier> supplier = Suppliers.ofSet();

        return toCollection(supplier);
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toLinkedHashSet() {
        final Supplier> supplier = Suppliers.ofLinkedHashSet();

        return toCollection(supplier);
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toImmutableSet() {
        final Collector> downstream = toSet();
        @SuppressWarnings("rawtypes")
        final Function, ImmutableSet> finisher = (Function) ImmutableSet_Finisher;

        return collectingAndThen(downstream, finisher);
    }

    /**
     *
     * @param 
     * @return
     * @see java.util.stream.Collectors#toUnmodifiableSet
     */
    public static  Collector> toUnmodifiableSet() {
        return java.util.stream.Collectors.toUnmodifiableSet();
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toQueue() {
        final Supplier> supplier = Suppliers.ofQueue();

        return toCollection(supplier);
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toDeque() {
        final Supplier> supplier = Suppliers.ofDeque();

        return toCollection(supplier);
    }

    /**
     *
     * @param 
     * @param atMostSize
     * @return
     */
    public static  Collector> toList(final int atMostSize) {
        final Supplier> supplier = () -> new ArrayList<>(N.min(256, atMostSize));

        return toCollection(supplier, atMostSize);
    }

    /**
     *
     * @param 
     * @param atMostSize
     * @return
     */
    public static  Collector> toSet(final int atMostSize) {
        final Supplier> supplier = () -> N.newHashSet(atMostSize);

        return toCollection(supplier, atMostSize);
    }

    /**
     *
     * @param 
     * @param 
     * @param collectionFactory
     * @return
     */
    public static > Collector toCollection(final Supplier collectionFactory) {
        final BiConsumer accumulator = BiConsumers.ofAdd();
        final BinaryOperator combiner = BinaryOperators.ofAddAllToBigger();

        return create(collectionFactory, accumulator, combiner, CH_ID);
    }

    /**
     *
     * @param 
     * @param 
     * @param collectionFactory
     * @param atMostSize
     * @return
     */
    public static > Collector toCollection(final Supplier collectionFactory, final int atMostSize) {
        final BiConsumer accumulator = (c, t) -> {
            if (c.size() < atMostSize) {
                c.add(t);
            }
        };

        final BinaryOperator combiner = (a, b) -> {
            if (a.size() < atMostSize) {
                final int n = atMostSize - a.size();

                if (b.size() <= n) {
                    a.addAll(b);
                } else {
                    if (b instanceof List) {
                        a.addAll(((List) b).subList(0, n));
                    } else {
                        final Iterator iter = b.iterator();

                        while (iter.hasNext() && a.size() < atMostSize) {
                            a.add(iter.next());
                        }
                    }
                }
            }

            return a;
        };

        return create(collectionFactory, accumulator, combiner, CH_ID);
    }

    /**
     *
     * @param 
     * @param 
     * @param supplier
     * @param accumulator
     * @return
     */
    public static > Collector toCollection(final Supplier supplier, final BiConsumer accumulator) {
        final BinaryOperator combiner = BinaryOperators.ofAddAllToBigger();

        return toCollection(supplier, accumulator, combiner);
    }

    /**
     *
     * @param 
     * @param 
     * @param supplier
     * @param accumulator
     * @param combiner
     * @return
     */
    public static > Collector toCollection(final Supplier supplier, final BiConsumer accumulator,
            final BinaryOperator combiner) {
        return create(supplier, accumulator, combiner, CH_ID);
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector> toMultiset() {
        final Supplier> supplier = Suppliers.ofMultiset();

        return toMultiset(supplier);
    }

    /**
     *
     * @param 
     * @param supplier
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static  Collector> toMultiset(final Supplier> supplier) {
        final BiConsumer, T> accumulator = (BiConsumer) Multiset_Accumulator;
        final BinaryOperator> combiner = (BinaryOperator) Multiset_Combiner;

        return create(supplier, accumulator, combiner, CH_UNORDERED_ID);
    }

    /**
     *
     * @param 
     * @return
     */
    public static  Collector toArray() {
        return toArray(Suppliers.ofEmptyObjectArray());
    }

    /**
     *
     * @param 
     * @param 
     * @param arraySupplier
     * @return
     */
    public static  Collector toArray(final Supplier arraySupplier) {
        final Supplier> supplier = Suppliers.ofList();
        @SuppressWarnings("rawtypes")
        final BiConsumer, T> accumulator = (BiConsumer) BiConsumers.ofAdd();
        final BinaryOperator> combiner = BinaryOperators.ofAddAllToBigger();
        final Function, A[]> finisher = t -> {
            final A[] a = arraySupplier.get();

            if (a.length >= t.size()) {
                return t.toArray(a);
            } else {
                return t.toArray((A[]) Array.newInstance(a.getClass().getComponentType(), t.size()));
            }
        };

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     *
     * @param 
     * @param 
     * @param arraySupplier
     * @return
     */
    public static  Collector toArray(final IntFunction arraySupplier) {
        final Supplier> supplier = Suppliers.ofList();
        @SuppressWarnings("rawtypes")
        final BiConsumer, T> accumulator = (BiConsumer) BiConsumers.ofAdd();
        final BinaryOperator> combiner = BinaryOperators.ofAddAllToBigger();
        final Function, A[]> finisher = t -> t.toArray(arraySupplier.apply(t.size()));

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toBooleanList() {
        final Supplier supplier = Suppliers.ofBooleanList();
        final BiConsumer accumulator = BooleanList_Accumulator;
        final BinaryOperator combiner = BooleanList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toBooleanArray() {
        final Supplier supplier = Suppliers.ofBooleanList();
        final BiConsumer accumulator = BooleanList_Accumulator;
        final BinaryOperator combiner = BooleanList_Combiner;
        final Function finisher = BooleanArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toCharList() {
        final Supplier supplier = Suppliers.ofCharList();
        final BiConsumer accumulator = CharList_Accumulator;
        final BinaryOperator combiner = CharList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toCharArray() {
        final Supplier supplier = Suppliers.ofCharList();
        final BiConsumer accumulator = CharList_Accumulator;
        final BinaryOperator combiner = CharList_Combiner;
        final Function finisher = CharArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toByteList() {
        final Supplier supplier = Suppliers.ofByteList();
        final BiConsumer accumulator = ByteList_Accumulator;
        final BinaryOperator combiner = ByteList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toByteArray() {
        final Supplier supplier = Suppliers.ofByteList();
        final BiConsumer accumulator = ByteList_Accumulator;
        final BinaryOperator combiner = ByteList_Combiner;
        final Function finisher = ByteArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toShortList() {
        final Supplier supplier = Suppliers.ofShortList();
        final BiConsumer accumulator = ShortList_Accumulator;
        final BinaryOperator combiner = ShortList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toShortArray() {
        final Supplier supplier = Suppliers.ofShortList();
        final BiConsumer accumulator = ShortList_Accumulator;
        final BinaryOperator combiner = ShortList_Combiner;
        final Function finisher = ShortArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toIntList() {
        final Supplier supplier = Suppliers.ofIntList();
        final BiConsumer accumulator = IntList_Accumulator;
        final BinaryOperator combiner = IntList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toIntArray() {
        final Supplier supplier = Suppliers.ofIntList();
        final BiConsumer accumulator = IntList_Accumulator;
        final BinaryOperator combiner = IntList_Combiner;
        final Function finisher = IntArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toLongList() {
        final Supplier supplier = Suppliers.ofLongList();
        final BiConsumer accumulator = LongList_Accumulator;
        final BinaryOperator combiner = LongList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toLongArray() {
        final Supplier supplier = Suppliers.ofLongList();
        final BiConsumer accumulator = LongList_Accumulator;
        final BinaryOperator combiner = LongList_Combiner;
        final Function finisher = LongArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toFloatList() {
        final Supplier supplier = Suppliers.ofFloatList();
        final BiConsumer accumulator = FloatList_Accumulator;
        final BinaryOperator combiner = FloatList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toFloatArray() {
        final Supplier supplier = Suppliers.ofFloatList();
        final BiConsumer accumulator = FloatList_Accumulator;
        final BinaryOperator combiner = FloatList_Combiner;
        final Function finisher = FloatArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toDoubleList() {
        final Supplier supplier = Suppliers.ofDoubleList();
        final BiConsumer accumulator = DoubleList_Accumulator;
        final BinaryOperator combiner = DoubleList_Combiner;

        return create(supplier, accumulator, combiner, CH_ID);
    }

    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector toDoubleArray() {
        final Supplier supplier = Suppliers.ofDoubleList();
        final BiConsumer accumulator = DoubleList_Accumulator;
        final BinaryOperator combiner = DoubleList_Combiner;
        final Function finisher = DoubleArray_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    private static final Supplier>> onlyOne_supplier = () -> Holder.of(Optional.empty());

    private static final BiConsumer>, Object> onlyOne_accumulator = (holder, val) -> {
        if (holder.value().isPresent()) {
            throw new TooManyElementsException("Duplicate values");
        }

        holder.setValue(Optional.of(val));
    };

    private static final BinaryOperator>> onlyOne_combiner = (t, u) -> {
        if (t.value().isPresent() && u.value().isPresent()) {
            throw new TooManyElementsException("Duplicate values");
        }

        return t.value().isPresent() ? t : u;
    };

    private static final Function>, Optional> onlyOne_finisher = Holder::value;

    /**
     * {@code TooManyElementsException} is threw if there are more than one values are collected.
     *
     * @param 
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static  Collector> onlyOne() {
        final Supplier>> supplier = (Supplier) onlyOne_supplier;
        final BiConsumer>, T> accumulator = (BiConsumer) onlyOne_accumulator;
        final BinaryOperator>> combiner = (BinaryOperator) onlyOne_combiner;
        final Function>, Optional> finisher = (Function) onlyOne_finisher;

        return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID);
    }

    /**
     * {@code TooManyElementsException} is threw if there are more than one values are collected.
     *
     * @param 
     * @param predicate
     * @return
     */
    public static  Collector> onlyOne(final Predicate predicate) {
        final Collector> downstream = onlyOne();

        return filtering(predicate, downstream);
    }

    private static final Supplier> first_last_supplier = () -> Holder.of(NONE);

    private static final BiConsumer, Object> first_accumulator = (holder, val) -> {
        if (holder.value() == NONE) {
            holder.setValue(val);
        }
    };

    private static final BiConsumer, Object> last_accumulator = Holder::setValue;

    private static final BinaryOperator> first_last_combiner = (t, u) -> {
        if (t.value() != NONE && u.value() != NONE) {
            throw new UnsupportedOperationException("The 'first' and 'last' Collector only can be used in sequential stream"); //NOSONAR
        }

        return t.value() != NONE ? t : u;
    };

    private static final Function, Optional> first_last_finisher = t -> t.value() == NONE ? Optional.empty() : Optional.of(t.value());

    /**
     * Only works for sequential Stream.
     *
     * @param 
     * @return
     * @throws UnsupportedOperationException operated by multiple threads
     */
    @SuppressWarnings("rawtypes")
    public static  Collector> first() {
        final Supplier> supplier = (Supplier) first_last_supplier;
        final BiConsumer, T> accumulator = (BiConsumer) first_accumulator;
        final BinaryOperator> combiner = (BinaryOperator) first_last_combiner;
        final Function, Optional> finisher = (Function) first_last_finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * Only works for sequential Stream.
     *
     * @param 
     * @return
     * @throws UnsupportedOperationException operated by multiple threads
     */
    @SuppressWarnings("rawtypes")
    public static  Collector> last() {
        final Supplier> supplier = (Supplier) first_last_supplier;
        final BiConsumer, T> accumulator = (BiConsumer) last_accumulator;
        final BinaryOperator> combiner = (BinaryOperator) first_last_combiner;
        final Function, Optional> finisher = (Function) first_last_finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * Only works for sequential Stream.
     *
     * @param 
     * @param n
     * @return
     * @throws IllegalArgumentException
     * @throws UnsupportedOperationException operated by multiple threads
     */
    public static  Collector> first(final int n) throws IllegalArgumentException {
        N.checkArgNotNegative(n, cs.n);

        final Supplier> supplier = () -> new ArrayList<>(N.min(256, n));

        final BiConsumer, T> accumulator = (c, t) -> {
            if (c.size() < n) {
                c.add(t);
            }
        };

        final BinaryOperator> combiner = (a, b) -> {
            if (N.notEmpty(a) && N.notEmpty(b)) {
                throw new UnsupportedOperationException("The 'first' and 'last' Collector only can be used in sequential stream");
            }

            return a.size() > 0 ? a : b;
        };

        return create(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * Only works for sequential Stream.
     *
     * @param 
     * @param n
     * @return
     * @throws IllegalArgumentException
     * @throws UnsupportedOperationException operated by multiple threads
     */
    public static  Collector> last(final int n) throws IllegalArgumentException {
        N.checkArgNotNegative(n, cs.n);

        final Supplier> supplier = () -> n <= 1024 ? new ArrayDeque<>(n) : new LinkedList<>();

        final BiConsumer, T> accumulator = (deque, t) -> {
            if (n > 0) {
                if (deque.size() >= n) {
                    deque.pollFirst();
                }

                deque.offerLast(t);
            }
        };

        final BinaryOperator> combiner = (a, b) -> {
            if (N.notEmpty(a) && N.notEmpty(b)) {
                throw new UnsupportedOperationException("The 'first' and 'last' Collector only can be used in sequential stream");
            }

            while (b.size() < n && !a.isEmpty()) {
                b.addFirst(a.pollLast());
            }

            return b;
        };

        final Function, List> finisher = ArrayList::new;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    public static Collector joining() {
        return joining("", "", "");
    }

    /**
     *
     * @param delimiter
     * @return
     */
    public static Collector joining(final CharSequence delimiter) {
        return joining(delimiter, "", "");
    }

    /**
     *
     * @param delimiter
     * @param prefix
     * @param suffix
     * @return
     */
    @SuppressWarnings("UnnecessaryLocalVariable")
    public static Collector joining(final CharSequence delimiter, final CharSequence prefix, final CharSequence suffix) {
        @SuppressWarnings("resource")
        final Supplier supplier = () -> Joiner.with(delimiter, prefix, suffix).reuseCachedBuffer();

        final BiConsumer accumulator = Joiner_Accumulator;
        final BinaryOperator combiner = Joiner_Combiner;
        final Function finisher = Joiner_Finisher;

        return create(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * It's copied from StreamEx: streamex under Apache License v2 and may be modified.
     * 
* * Returns a {@code Collector} which passes only those elements to the * specified downstream collector which match given predicate. * *

* This method returns a * short-circuiting * collector if downstream collector is short-circuiting. * *

* The operation performed by the returned collector is equivalent to * {@code stream.filter(predicate).collect(downstream)}. This collector is * mostly useful as a downstream collector in cascaded operation involving * {@link MoreCollectors#combine(Collector, Collector, BiFunction)} collector. * *

* This method is similar to {@code Collectors.filtering} method which * appears in JDK 9. However, when downstream collector is * short-circuiting * , this method will also return a short-circuiting collector. * * @param the type of the input elements * @param intermediate accumulation type of the downstream collector * @param result type of collector * @param predicate a filter function to be applied to the input elements * @param downstream a collector which will accept filtered values * @return a collector which applies the predicate to the input elements and * provides the elements for which predicate returned {@code true} to the * downstream collector * @see MoreCollectors#combine(Collector, Collector, BiFunction) */ public static Collector filtering(final Predicate predicate, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = (a, t) -> { if (predicate.test(t)) { downstreamAccumulator.accept(a, t); } }; return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which filters input elements by the supplied * predicate, collecting them to the list. * *

* This method behaves like * {@code filtering(predicate, Collectors.toList())}. * *

* There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * * @param the type of the input elements * @param predicate a filter function to be applied to the input elements * @return a collector which applies the predicate to the input elements and * collects the elements for which predicate returned {@code true} to the * {@code List} * @see #filtering(Predicate, Collector) */ @Beta public static Collector> filteringToList(final Predicate predicate) { final Collector> downstream = Collectors.toList(); return filtering(predicate, downstream); } /** * * @param * @param * @param * @param * @param mapper * @param downstream * @return */ public static Collector mapping(final Function mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = (a, t) -> downstreamAccumulator.accept(a, mapper.apply(t)); return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * @param * @param * @param mapper * @return */ @Beta public static Collector> mappingToList(final Function mapper) { return Collectors.mapping(mapper, Collectors. toList()); } /** * * @param * @param * @param * @param * @param mapper * @param downstream * @return */ public static Collector flatMapping(final Function> mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = (a, t) -> { try (Stream stream = mapper.apply(t)) { final ObjIterator iter = StreamBase.iterate(stream); while (iter.hasNext()) { downstreamAccumulator.accept(a, iter.next()); } } }; return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * @param * @param * @param mapper * @return */ @Beta public static Collector> flatMappingToList(final Function> mapper) { return flatMapping(mapper, Collectors. toList()); } /** * * @param * @param * @param * @param * @param mapper * @param downstream * @return */ public static Collector flatmapping(final Function> mapper, // NOSONAR final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = (a, t) -> { final Collection c = mapper.apply(t); if (N.notEmpty(c)) { for (final U u : c) { downstreamAccumulator.accept(a, u); } } }; return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * @param * @param * @param mapper * @return */ @Beta public static Collector> flatmappingToList(final Function> mapper) { // NOSONAR return flatmapping(mapper, Collectors. toList()); } /** * * @param * @param * @param * @param * @param * @param flatMapper * @param mapper * @param downstream * @return */ @Beta public static Collector flatMapping(final Function> flatMapper, // NOSONAR final BiFunction mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = (a, t) -> { try (Stream stream = flatMapper.apply(t)) { final ObjIterator iter = StreamBase.iterate(stream); while (iter.hasNext()) { downstreamAccumulator.accept(a, mapper.apply(t, iter.next())); } } }; return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * @param * @param * @param * @param flatMapper * @param mapper * @return */ @Beta public static Collector> flatMappingToList(final Function> flatMapper, // NOSONAR final BiFunction mapper) { return flatMapping(flatMapper, mapper, Collectors. toList()); } /** * * @param * @param * @param * @param * @param * @param flatMapper * @param mapper * @param downstream * @return */ @Beta public static Collector flatmapping(final Function> flatMapper, // NOSONAR final BiFunction mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = (a, t) -> { final Collection c = flatMapper.apply(t); if (N.notEmpty(c)) { for (final T2 t2 : c) { downstreamAccumulator.accept(a, mapper.apply(t, t2)); } } }; return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * @param * @param * @param * @param flatMapper * @param mapper * @return */ @Beta public static Collector> flatmappingToList(final Function> flatMapper, // NOSONAR final BiFunction mapper) { return flatmapping(flatMapper, mapper, Collectors. toList()); } // // Too many/much? // /** // * // * // * @param // * @param // * @param // * @param // * @param mapper // * @param downstream // * @return // */ // public static Collector flattMapping(final Function> mapper, // final Collector downstream) { // final BiConsumer downstreamAccumulator = downstream.accumulator(); // // final BiConsumer accumulator = (a, t) -> { // try (java.util.stream.Stream stream = mapper.apply(t)) { // final Iterator iter = stream.iterator(); // // while (iter.hasNext()) { // downstreamAccumulator.accept(a, iter.next()); // } // } // }; // // return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); // } // // /** // * // * // * @param // * @param // * @param mapper // * @return // */ // @Beta // public static Collector> flattMappingToList(final Function> mapper) { // return flattMapping(mapper, Collectors. toList()); // } // // /** // * // * // * @param // * @param // * @param // * @param // * @param // * @param flatMapper // * @param mapper // * @param downstream // * @return // */ // @Beta // public static Collector flattMapping(final Function> flatMapper, // final BiFunction mapper, final Collector downstream) { // final BiConsumer downstreamAccumulator = downstream.accumulator(); // // final BiConsumer accumulator = (a, t) -> { // try (java.util.stream.Stream stream = flatMapper.apply(t)) { // final Iterator iter = stream.iterator(); // // while (iter.hasNext()) { // downstreamAccumulator.accept(a, mapper.apply(t, iter.next())); // } // } // }; // // return create(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); // } // // /** // * // * // * @param // * @param // * @param // * @param flatMapper // * @param mapper // * @return // */ // @Beta // public static Collector> flattMappingToList(final Function> flatMapper, // final BiFunction mapper) { // return flattMapping(flatMapper, mapper, Collectors. toList()); // } /** * * @param * @param * @param * @param * @param downstream * @param finisher * @return * @throws IllegalArgumentException */ public static Collector collectingAndThen(final Collector downstream, final Function finisher) throws IllegalArgumentException { N.checkArgNotNull(downstream); N.checkArgNotNull(finisher); final Function downstreamFinisher = downstream.finisher(); final Function thenFinisher = t -> finisher.apply(downstreamFinisher.apply(t)); Set characteristics = downstream.characteristics(); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { if (characteristics.size() == 1) { characteristics = N.emptySet(); } else { characteristics = EnumSet.copyOf(characteristics); characteristics.remove(Characteristics.IDENTITY_FINISH); characteristics = Collections.unmodifiableSet(characteristics); } } return create(downstream.supplier(), downstream.accumulator(), downstream.combiner(), thenFinisher, characteristics); } /** * * @param * @param * @param * @param collector * @return * @throws IllegalArgumentException */ @Beta public static Collector> collectingOrEmpty(final Collector collector) throws IllegalArgumentException { N.checkArgNotNull(collector); final MutableBoolean accumulated = MutableBoolean.of(false); final BiConsumer downstreamAccumulator = collector.accumulator(); final Function downstreamFinisher = collector.finisher(); final BiConsumer newAccumulator = (a, t) -> { downstreamAccumulator.accept(a, t); accumulated.setTrue(); }; final Function> newFinisher = a -> { if (accumulated.isTrue()) { return Optional.of(downstreamFinisher.apply(a)); } else { return Optional.empty(); } }; Set characteristics = collector.characteristics(); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { if (characteristics.size() == 1) { characteristics = N.emptySet(); } else { characteristics = EnumSet.copyOf(characteristics); characteristics.remove(Characteristics.IDENTITY_FINISH); characteristics = Collections.unmodifiableSet(characteristics); } } return create(collector.supplier(), newAccumulator, collector.combiner(), newFinisher, characteristics); } /** * * @param * @param * @param * @param collector * @param defaultForEmpty * @return */ @Beta public static Collector collectingOrElseIfEmpty(final Collector collector, final R defaultForEmpty) { return collectingOrElseGetIfEmpty(collector, () -> defaultForEmpty); } /** * * @param * @param * @param * @param collector * @param defaultForEmpty * @return * @throws IllegalArgumentException */ @Beta public static Collector collectingOrElseGetIfEmpty(final Collector collector, final Supplier defaultForEmpty) throws IllegalArgumentException { N.checkArgNotNull(collector); final MutableBoolean accumulated = MutableBoolean.of(false); final BiConsumer downstreamAccumulator = collector.accumulator(); final Function downstreamFinisher = collector.finisher(); final BiConsumer newAccumulator = (a, t) -> { downstreamAccumulator.accept(a, t); accumulated.setTrue(); }; final Function newFinisher = a -> { if (accumulated.isTrue()) { return downstreamFinisher.apply(a); } else { return defaultForEmpty.get(); } }; Set characteristics = collector.characteristics(); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { if (characteristics.size() == 1) { characteristics = N.emptySet(); } else { characteristics = EnumSet.copyOf(characteristics); characteristics.remove(Characteristics.IDENTITY_FINISH); characteristics = Collections.unmodifiableSet(characteristics); } } return create(collector.supplier(), newAccumulator, collector.combiner(), newFinisher, characteristics); } /** * * @param * @param * @param * @param collector * @return */ @Beta public static Collector collectingOrElseThrowIfEmpty(final Collector collector) { return collectingOrElseGetIfEmpty(collector, () -> { throw noSuchElementExceptionSupplier.get(); }); } /** * * @param * @param * @param * @param collector * @param exceptionSupplier * @return */ @Beta public static Collector collectingOrElseThrowIfEmpty(final Collector collector, final Supplier exceptionSupplier) { return collectingOrElseGetIfEmpty(collector, () -> { throw exceptionSupplier.get(); }); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which collects into the {@link List} the * input elements for which given mapper function returns distinct results. * *

* For ordered source, the order of collected elements is preserved. If the * same result is returned by mapper function for several elements, only the * first element is included in the resulting list. * *

* There are no guarantees on the type, mutability, serializability, or * thread-safety of the {@code List} returned. * *

* The operation performed by the returned collector is equivalent to * {@code stream.distinct(mapper).toList()}, but may work faster. * * @param the type of the input elements * @param keyMapper a function which classifies input elements. * @return a collector which collects distinct elements to the {@code List}. */ public static Collector> distinctByToList(final Function keyMapper) { return distinctByToCollection(keyMapper, Suppliers.ofList()); } /** * * @param * @param * @param keyMapper * @param supplier * @return */ public static > Collector distinctByToCollection(final Function keyMapper, final Supplier supplier) { final Supplier> mappSupplier = Suppliers.ofLinkedHashMap(); final BiConsumer, T> accumulator = (map, t) -> { final Object key = keyMapper.apply(t); if (!map.containsKey(key)) { map.put(key, t); } }; final BinaryOperator> combiner = (a, b) -> { for (final Map.Entry entry : b.entrySet()) { if (!a.containsKey(entry.getKey())) { a.put(entry.getKey(), entry.getValue()); } } return a; }; final Function, C> finisher = map -> { final C c = supplier.get(); c.addAll(map.values()); return c; }; return create(mappSupplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which counts a number of distinct values the * mapper function returns for the stream elements. * *

* The operation performed by the returned collector is equivalent to * {@code stream.map(mapper).distinct().count()}. This collector is mostly * useful as a downstream collector. * * @param the type of the input elements * @param keyMapper a function which classifies input elements. * @return a collector which counts a number of distinct classes the mapper * function returns for the stream elements. */ public static Collector distinctByToCounting(final Function keyMapper) { final Supplier> supplier = Suppliers.ofSet(); final BiConsumer, T> accumulator = (c, t) -> c.add(keyMapper.apply(t)); final BinaryOperator> combiner = BinaryOperators.ofAddAllToBigger(); final Function, Integer> finisher = Set::size; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @return */ public static Collector counting() { return summingLong(it -> 1L); } /** * * @param * @return */ public static Collector countingToInt() { return summingInt(it -> 1); } /** * * @param * @return */ public static > Collector> min() { return min(Comparators.nullsLast()); } /** * * @param * @param comparator * @return * @throws IllegalArgumentException */ public static Collector> min(final Comparator comparator) throws IllegalArgumentException { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) <= 0 ? a : b; return reducing(op); } /** * * @param * @param defaultForEmpty * @return */ public static > Collector minOrElse(final T defaultForEmpty) { return minOrElseGet(() -> defaultForEmpty); } /** * * @param * @param comparator * @param defaultForEmpty * @return */ public static Collector minOrElse(final Comparator comparator, final T defaultForEmpty) { return minOrElseGet(comparator, () -> defaultForEmpty); } /** * * @param * @param supplierForEmpty * @return */ public static > Collector minOrElseGet(final Supplier supplierForEmpty) { return minOrElseGet(Comparators.nullsLast(), supplierForEmpty); } /** * * @param * @param comparator * @param supplierForEmpty * @return * @throws IllegalArgumentException */ public static Collector minOrElseGet(final Comparator comparator, final Supplier supplierForEmpty) throws IllegalArgumentException { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) <= 0 ? a : b; return reducingOrElseGet(op, supplierForEmpty); } /** * * @param * @return */ public static > Collector minOrElseThrow() { return minOrElseThrow(Comparators.nullsLast()); } /** * * @param * @param comparator * @return */ public static Collector minOrElseThrow(final Comparator comparator) { return minOrElseThrow(comparator, noSuchElementExceptionSupplier); } /** * * @param * @param comparator * @param exceptionSupplier * @return * @throws IllegalArgumentException */ public static Collector minOrElseThrow(final Comparator comparator, final Supplier exceptionSupplier) throws IllegalArgumentException { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) <= 0 ? a : b; return reducingOrElseThrow(op, exceptionSupplier); } private static final Supplier noSuchElementExceptionSupplier = NoSuchElementException::new; /** * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector> minBy(final Function keyMapper) { return min(Comparators.nullsLastBy(keyMapper)); } /** * * @param * @param keyMapper * @param supplierForEmpty * @return */ @SuppressWarnings("rawtypes") public static Collector minByOrElseGet(final Function keyMapper, final Supplier supplierForEmpty) { return minOrElseGet(Comparators.nullsLastBy(keyMapper), supplierForEmpty); } /** * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector minByOrElseThrow(final Function keyMapper) { return minOrElseThrow(Comparators.nullsLastBy(keyMapper)); } /** * * @param * @param keyMapper * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector minByOrElseThrow(final Function keyMapper, final Supplier exceptionSupplier) { return minOrElseThrow(Comparators.nullsLastBy(keyMapper), exceptionSupplier); } /** * * @param * @return */ public static > Collector> max() { return max(Comparators.nullsFirst()); } /** * * @param * @param comparator * @return * @throws IllegalArgumentException */ public static Collector> max(final Comparator comparator) throws IllegalArgumentException { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) >= 0 ? a : b; return reducing(op); } /** * * @param * @param defaultForEmpty * @return */ public static > Collector maxOrElse(final T defaultForEmpty) { return maxOrElseGet(() -> defaultForEmpty); } /** * * @param * @param comparator * @param defaultForEmpty * @return */ public static Collector maxOrElse(final Comparator comparator, final T defaultForEmpty) { return maxOrElseGet(comparator, () -> defaultForEmpty); } /** * * @param * @param supplierForEmpty * @return */ public static > Collector maxOrElseGet(final Supplier supplierForEmpty) { return maxOrElseGet(Comparators.nullsFirst(), supplierForEmpty); } /** * * @param * @param comparator * @param supplierForEmpty * @return * @throws IllegalArgumentException */ public static Collector maxOrElseGet(final Comparator comparator, final Supplier supplierForEmpty) throws IllegalArgumentException { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) >= 0 ? a : b; return reducingOrElseGet(op, supplierForEmpty); } /** * * @param * @return */ public static > Collector maxOrElseThrow() { return maxOrElseThrow(Comparators.nullsFirst()); } /** * * @param * @param comparator * @return */ public static Collector maxOrElseThrow(final Comparator comparator) { return maxOrElseThrow(comparator, noSuchElementExceptionSupplier); } /** * * @param * @param comparator * @param exceptionSupplier * @return * @throws IllegalArgumentException */ public static Collector maxOrElseThrow(final Comparator comparator, final Supplier exceptionSupplier) throws IllegalArgumentException { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) >= 0 ? a : b; return reducingOrElseThrow(op, exceptionSupplier); } /** * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector> maxBy(final Function keyMapper) { return max(Comparators.nullsFirstBy(keyMapper)); } /** * * @param * @param keyMapper * @param supplierForEmpty * @return */ @SuppressWarnings("rawtypes") public static Collector maxByOrElseGet(final Function keyMapper, final Supplier supplierForEmpty) { return maxOrElseGet(Comparators.nullsFirstBy(keyMapper), supplierForEmpty); } /** * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector maxByOrElseThrow(final Function keyMapper) { return maxOrElseThrow(Comparators.nullsFirstBy(keyMapper)); } /** * * @param * @param keyMapper * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector maxByOrElseThrow(final Function keyMapper, final Supplier exceptionSupplier) { return maxOrElseThrow(Comparators.nullsFirstBy(keyMapper), exceptionSupplier); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the natural * order. The found elements are collected to {@link List}. * * @param the type of the input elements * @return a {@code Collector} which finds all the minimal elements and * collects them to the {@code List}. * @see #minAll(Comparator) * @see #minAll(Collector) */ public static > Collector> minAll() { return minAll(Comparators.nullsLast()); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the * specified {@link Comparator}. The found elements are collected to * {@link List}. * * @param the type of the input elements * @param comparator a {@code Comparator} to compare the elements * @return a {@code Collector} which finds all the minimal elements and * collects them to the {@code List}. * @see #minAll(Comparator, Collector) * @see #minAll() */ public static Collector> minAll(final Comparator comparator) { return minAll(comparator, Integer.MAX_VALUE); } /** * * @param * @param comparator * @param atMostSize * @return */ public static Collector> minAll(final Comparator comparator, final int atMostSize) { return maxAll(Comparators.reverseOrder(comparator), atMostSize); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the natural * order. The found elements are reduced using the specified downstream * {@code Collector}. * * @param the type of the input elements * @param the intermediate accumulation type of the downstream collector * @param the result type of the downstream reduction * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the minimal elements. * @see #minAll(Comparator, Collector) * @see #minAll(Comparator) * @see #minAll() */ @SuppressWarnings("rawtypes") public static Collector minAll(final Collector downstream) { return minAll(Comparators.nullsLast(), downstream); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and smaller than any other element according to the * specified {@link Comparator}. The found elements are reduced using the * specified downstream {@code Collector}. * * @param the type of the input elements * @param the intermediate accumulation type of the downstream collector * @param the result type of the downstream reduction * @param comparator a {@code Comparator} to compare the elements * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the minimal elements. * @see #minAll(Comparator) * @see #minAll(Collector) * @see #minAll() */ public static Collector minAll(final Comparator comparator, final Collector downstream) { return maxAll(Comparators.reverseOrder(comparator), downstream); } /** * * @param * @param * @param downstream * @return */ @SuppressWarnings("rawtypes") public static Collector>> minAlll(final Collector downstream) { return minAlll(Comparators.nullsLast(), downstream); } /** * * @param * @param * @param comparator * @param downstream * @return */ public static Collector>> minAlll(final Comparator comparator, final Collector downstream) { return minAlll(comparator, downstream, Fn.identity()); } /** * * @param * @param * @param * @param comparator * @param downstream * @param finisher * @return */ public static Collector minAlll(final Comparator comparator, final Collector downstream, final Function>, RR> finisher) { return maxAlll(Comparators.reverseOrder(comparator), downstream, finisher); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the natural * order. The found elements are collected to {@link List}. * * @param the type of the input elements * @return a {@code Collector} which finds all the maximal elements and * collects them to the {@code List}. * @see #maxAll(Comparator) * @see #maxAll(Collector) */ public static > Collector> maxAll() { return maxAll(Comparators.nullsFirst()); } /** * It's copied from StreamEx: streamex under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the * specified {@link Comparator}. The found elements are collected to * {@link List}. * * @param the type of the input elements * @param comparator a {@code Comparator} to compare the elements * @return a {@code Collector} which finds all the maximal elements and * collects them to the {@code List}. * @see #maxAll(Comparator, Collector) * @see #maxAll() */ public static Collector> maxAll(final Comparator comparator) { return maxAll(comparator, Integer.MAX_VALUE); } /** * * @param * @param comparator * @param atMostSize * @return */ public static Collector> maxAll(final Comparator comparator, final int atMostSize) { final Supplier>> supplier = () -> { final List list = new ArrayList<>(Math.min(16, atMostSize)); return Pair.of((T) NONE, list); }; final BiConsumer>, T> accumulator = (a, t) -> { if (a.left == NONE) { a.left = t; if (a.right.size() < atMostSize) { a.right.add(t); } } else { final int cmp = comparator.compare(t, a.left); if (cmp > 0) { a.left = t; a.right.clear(); } if ((cmp >= 0) && (a.right.size() < atMostSize)) { a.right.add(t); } } }; final BinaryOperator>> combiner = (a, b) -> { if (b.left == NONE) { return a; } else if (a.left == NONE) { return b; } final int cmp = comparator.compare(a.left, b.left); if (cmp > 0) { return a; } else if (cmp < 0) { return b; } if (a.right.size() < atMostSize) { if (b.right.size() <= atMostSize - a.right.size()) { a.right.addAll(b.right); } else { a.right.addAll(b.right.subList(0, atMostSize - a.right.size())); } } return a; }; final Function>, List> finisher = a -> a.right; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the natural * order. The found elements are reduced using the specified downstream * {@code Collector}. * * @param the type of the input elements * @param the result type of the downstream reduction * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the maximal elements. * @see #maxAll(Comparator, Collector) * @see #maxAll(Comparator) * @see #maxAll() */ @SuppressWarnings("rawtypes") public static Collector maxAll(final Collector downstream) { return maxAll(Comparators.nullsFirst(), downstream); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds all the elements which are equal * to each other and bigger than any other element according to the * specified {@link Comparator}. The found elements are reduced using the * specified downstream {@code Collector}. * * @param the type of the input elements * @param the result type of the downstream reduction * @param comparator a {@code Comparator} to compare the elements * @param downstream a {@code Collector} implementing the downstream * reduction * @return a {@code Collector} which finds all the maximal elements. * @see #maxAll(Comparator) * @see #maxAll(Collector) * @see #maxAll() */ @SuppressWarnings("rawtypes") public static Collector maxAll(final Comparator comparator, final Collector downstream) { final Supplier downstreamSupplier = (Supplier) downstream.supplier(); final BiConsumer downstreamAccumulator = (BiConsumer) downstream.accumulator(); final BinaryOperator downstreamCombiner = (BinaryOperator) downstream.combiner(); final Function downstreamFinisher = (Function) downstream.finisher(); final MutableBoolean isCollection = MutableBoolean.of(false); final MutableBoolean isMap = MutableBoolean.of(false); final Supplier> supplier = () -> { final Object container = downstreamSupplier.get(); if (container instanceof Collection coll && coll.isEmpty()) { try { //noinspection RedundantOperationOnEmptyContainer coll.clear(); isCollection.setTrue(); } catch (final Exception e) { // ignore } } else if (container instanceof Map map && map.isEmpty()) { try { //noinspection RedundantOperationOnEmptyContainer map.clear(); isMap.setTrue(); } catch (final Exception e) { // ignore } } return Pair.of((T) none(), container); }; final BiConsumer, T> accumulator = (a, t) -> { if (a.left == NONE) { a.left = t; downstreamAccumulator.accept(a.right, t); } else { final int cmp = comparator.compare(t, a.left); if (cmp > 0) { if (isCollection.isTrue()) { ((Collection) a.right).clear(); } else if (isMap.isTrue()) { ((Map) a.right).clear(); } else { a.right = downstreamSupplier.get(); } a.left = t; } if (cmp >= 0) { downstreamAccumulator.accept(a.right, t); } } }; final BinaryOperator> combiner = (a, b) -> { if (b.left == NONE) { return a; } else if (a.left == NONE) { return b; } final int cmp = comparator.compare(a.left, b.left); if (cmp > 0) { return a; } else if (cmp < 0) { return b; } a.right = downstreamCombiner.apply(a.right, b.right); return a; }; final Function, R> finisher = t -> downstreamFinisher.apply(t.right); return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param downstream * @return */ @SuppressWarnings("rawtypes") public static Collector>> maxAlll(final Collector downstream) { return maxAlll(Comparators.nullsFirst(), downstream); } /** * * @param * @param * @param comparator * @param downstream * @return */ public static Collector>> maxAlll(final Comparator comparator, final Collector downstream) { return maxAlll(comparator, downstream, Fn.identity()); } /** * * @param * @param * @param * @param comparator * @param downstream * @param finisher * @return */ @SuppressWarnings("rawtypes") public static Collector maxAlll(final Comparator comparator, final Collector downstream, final Function>, RR> finisher) { final Supplier downstreamSupplier = (Supplier) downstream.supplier(); final BiConsumer downstreamAccumulator = (BiConsumer) downstream.accumulator(); final BinaryOperator downstreamCombiner = (BinaryOperator) downstream.combiner(); final Function downstreamFinisher = (Function) downstream.finisher(); final MutableBoolean isCollection = MutableBoolean.of(false); final MutableBoolean isMap = MutableBoolean.of(false); final Supplier> supplier = () -> { final Object container = downstreamSupplier.get(); if (container instanceof Collection coll && coll.isEmpty()) { try { //noinspection RedundantOperationOnEmptyContainer coll.clear(); isCollection.setTrue(); } catch (final Exception e) { // ignore } } else if (container instanceof Map map && map.isEmpty()) { try { //noinspection RedundantOperationOnEmptyContainer map.clear(); isMap.setTrue(); } catch (final Exception e) { // ignore } } return Pair.of((T) none(), container); }; final BiConsumer, T> accumulator = (a, t) -> { if (a.left == NONE) { a.left = t; downstreamAccumulator.accept(a.right, t); } else { final int cmp = comparator.compare(t, a.left); if (cmp > 0) { if (isCollection.isTrue()) { ((Collection) a.right).clear(); } else if (isMap.isTrue()) { ((Map) a.right).clear(); } else { a.right = downstreamSupplier.get(); } a.left = t; } if (cmp >= 0) { downstreamAccumulator.accept(a.right, t); } } }; final BinaryOperator> combiner = (a, b) -> { if (b.left == NONE) { return a; } else if (a.left == NONE) { return b; } final int cmp = comparator.compare(a.left, b.left); if (cmp > 0) { return a; } else if (cmp < 0) { return b; } else { a.right = downstreamCombiner.apply(a.right, b.right); return a; } }; final Function, RR> finalFinisher = a -> { final Optional> result = a.left == NONE ? Optional.empty() : Optional.of(Pair.of(a.left, downstreamFinisher.apply(a.right))); return finisher.apply(result); }; return create(supplier, accumulator, combiner, finalFinisher, CH_UNORDERED_NOID); } /** * * @param * @return */ @SuppressWarnings("rawtypes") public static Collector>> minMax() { return minMax(Comparators.naturalOrder()); } /** * * @param * @param comparator * @return * @see Collectors#minMax(Comparator, BiFunction) */ public static Collector>> minMax(final Comparator comparator) { return minMax(comparator, Fn.pair()); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which finds the minimal and maximal element * according to the supplied comparator, then applies finisher function to * them producing the final result. * *

* This collector produces a stable result for ordered stream: if several * minimal or maximal elements appear, the collector always selects the * first encountered. * *

* If there are no input elements, the finisher method is not called and * empty {@code Optional} is returned. Otherwise, the finisher result is * wrapped into {@code Optional}. * * @param the type of the input elements * @param the type of the result wrapped into {@code Optional} * @param comparator comparator which is used to find the minimal and maximal elements * @param finisher a {@link BiFunction} which takes the minimal and maximal elements and produces the final result. * @return a {@code Collector} which finds minimal and maximal elements. */ public static Collector> minMax(final Comparator comparator, final BiFunction finisher) { final BiFunction, Optional, Optional> finisher2 = (min, max) -> min.isPresent() ? Optional.of((R) finisher.apply(min.get(), max.get())) : Optional.empty(); return MoreCollectors.combine(Collectors.min(comparator), Collectors.max(comparator), finisher2); } /** * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector>> minMaxBy(final Function keyMapper) { return minMax(Comparators.comparingBy(keyMapper)); } /** * * @param * @param * @param keyMapper * @param finisher * @return */ @SuppressWarnings("rawtypes") public static Collector> minMaxBy(final Function keyMapper, final BiFunction finisher) { return minMax(Comparators.comparingBy(keyMapper), finisher); } /** * * @param * @param supplierForEmpty * @return */ public static > Collector> minMaxOrElseGet( final Supplier> supplierForEmpty) { return minMaxOrElseGet(Comparators.naturalOrder(), supplierForEmpty); } /** * * @param * @param comparator * @param supplierForEmpty * @return */ public static Collector> minMaxOrElseGet(final Comparator comparator, final Supplier> supplierForEmpty) { return MoreCollectors.combine(Collectors.min(comparator), Collectors.max(comparator), (min, max) -> { if (min.isPresent()) { return Pair.of(min.get(), max.get()); } else { return (Pair) supplierForEmpty.get(); } }); } /** * * @param * @return */ public static > Collector> minMaxOrElseThrow() { return minMaxOrElseThrow(Comparators.naturalOrder()); } /** * * @param * @param comparator * @return */ public static Collector> minMaxOrElseThrow(final Comparator comparator) { return MoreCollectors.combine(Collectors.minOrElseThrow(comparator), Collectors.maxOrElseThrow(comparator), Fn.pair()); } @SuppressWarnings("unchecked") static T none() { //NOSONAR return (T) NONE; } /** * * @param * @param mapper * @return */ public static Collector summingInt(final ToIntFunction mapper) { final BiConsumer accumulator = (a, t) -> a[0] += mapper.applyAsInt(t); return create(SummingInt_Supplier, accumulator, SummingInt_Combiner, SummingInt_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector summingIntToLong(final ToIntFunction mapper) { final BiConsumer accumulator = (a, t) -> a[0] += mapper.applyAsInt(t); return create(SummingIntToLong_Supplier, accumulator, SummingIntToLong_Combiner, SummingIntToLong_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector summingLong(final ToLongFunction mapper) { final BiConsumer accumulator = (a, t) -> a[0] += mapper.applyAsLong(t); return create(SummingLong_Supplier, accumulator, SummingLong_Combiner, SummingLong_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector summingDouble(final ToDoubleFunction mapper) { final BiConsumer accumulator = (a, t) -> a.add(mapper.applyAsDouble(t)); return create(SummingDouble_Supplier, accumulator, SummingDouble_Combiner, SummingDouble_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector summingBigInteger(final Function mapper) { final BiConsumer accumulator = (a, t) -> a[0] = a[0].add(mapper.apply(t)); return create(SummingBigInteger_Supplier, accumulator, SummingBigInteger_Combiner, SummingBigInteger_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector summingBigDecimal(final Function mapper) { final BiConsumer accumulator = (a, t) -> a[0] = a[0].add(mapper.apply(t)); return create(SummingBigDecimal_Supplier, accumulator, SummingBigDecimal_Combiner, SummingBigDecimal_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingInt(final ToIntFunction mapper) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; }; return create(AveragingInt_Supplier, accumulator, AveragingInt_Combiner, AveragingInt_Finisher_op, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingIntOrElseThrow(final ToIntFunction mapper) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; }; return create(AveragingInt_Supplier, accumulator, AveragingInt_Combiner, AveragingInt_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingLong(final ToLongFunction mapper) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; }; return create(AveragingLong_Supplier, accumulator, AveragingLong_Combiner, AveragingLong_Finisher_op, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingLongOrElseThrow(final ToLongFunction mapper) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; }; return create(AveragingLong_Supplier, accumulator, AveragingLong_Combiner, AveragingLong_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingDouble(final ToDoubleFunction mapper) { final BiConsumer accumulator = (a, t) -> a.add(mapper.applyAsDouble(t)); return create(AveragingDouble_Supplier, accumulator, AveragingDouble_Combiner, AveragingDouble_Finisher_op, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingDoubleOrElseThrow(final ToDoubleFunction mapper) { final BiConsumer accumulator = (a, t) -> a.add(mapper.applyAsDouble(t)); return create(AveragingDouble_Supplier, accumulator, AveragingDouble_Combiner, AveragingDouble_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector> averagingBigInteger(final Function mapper) { final BiConsumer, T> accumulator = (a, t) -> { a.setLeft(a.left.add(mapper.apply(t))); a.right[0] += 1; }; return create(AveragingBigInteger_Supplier, accumulator, AveragingBigInteger_Combiner, AveragingBigInteger_Finisher_op, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingBigIntegerOrElseThrow(final Function mapper) { final BiConsumer, T> accumulator = (a, t) -> { a.setLeft(a.left.add(mapper.apply(t))); a.right[0] += 1; }; return create(AveragingBigInteger_Supplier, accumulator, AveragingBigInteger_Combiner, AveragingBigInteger_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector> averagingBigDecimal(final Function mapper) { final BiConsumer, T> accumulator = (a, t) -> { a.setLeft(a.left.add(mapper.apply(t))); a.right[0] += 1; }; return create(AveragingBigDecimal_Supplier, accumulator, AveragingBigDecimal_Combiner, AveragingBigDecimal_Finisher_op, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ public static Collector averagingBigDecimalOrElseThrow(final Function mapper) { final BiConsumer, T> accumulator = (a, t) -> { a.setLeft(a.left.add(mapper.apply(t))); a.right[0] += 1; }; return create(AveragingBigDecimal_Supplier, accumulator, AveragingBigDecimal_Combiner, AveragingBigDecimal_Finisher, CH_UNORDERED_NOID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingChar(final ToCharFunction mapper) { // NOSONAR final Supplier supplier = SummarizingChar_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsChar(t)); final BinaryOperator combiner = SummarizingChar_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingByte(final ToByteFunction mapper) { // NOSONAR final Supplier supplier = SummarizingByte_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsByte(t)); final BinaryOperator combiner = SummarizingByte_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingShort(final ToShortFunction mapper) { // NOSONAR final Supplier supplier = SummarizingShort_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsShort(t)); final BinaryOperator combiner = SummarizingShort_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingInt(final ToIntFunction mapper) { final Supplier supplier = SummarizingInt_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsInt(t)); final BinaryOperator combiner = SummarizingInt_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingLong(final ToLongFunction mapper) { final Supplier supplier = SummarizingLong_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsLong(t)); final BinaryOperator combiner = SummarizingLong_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingFloat(final ToFloatFunction mapper) { // NOSONAR final Supplier supplier = SummarizingFloat_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsFloat(t)); final BinaryOperator combiner = SummarizingFloat_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingDouble(final ToDoubleFunction mapper) { final Supplier supplier = SummarizingDouble_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsDouble(t)); final BinaryOperator combiner = SummarizingDouble_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingBigInteger(final Function mapper) { final Supplier supplier = SummarizingBigInteger_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.apply(t)); final BinaryOperator combiner = SummarizingBigInteger_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param mapper * @return */ @SuppressWarnings("UnnecessaryLocalVariable") public static Collector summarizingBigDecimal(final Function mapper) { final Supplier supplier = SummarizingBigDecimal_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.apply(t)); final BinaryOperator combiner = SummarizingBigDecimal_Combiner; return create(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param identity * @param op * @return */ public static Collector reducing(final T identity, final BinaryOperator op) { final BiConsumer, T> accumulator = (a, t) -> a.setValue(op.apply(a.value(), t)); final BinaryOperator> combiner = (a, b) -> { a.setValue(op.apply(a.value(), b.value())); return a; }; @SuppressWarnings("rawtypes") final Function, T> finisher = (Function) Reducing_Finisher_0; return create(holderSupplier(identity), accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param op * @return */ @SuppressWarnings("rawtypes") public static Collector> reducing(final BinaryOperator op) { final Supplier> supplier = () -> new OptHolder<>(op); final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner; final Function, Optional> finisher = (Function) Reducing_Finisher; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param op * @param supplierForEmpty * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrElseGet(final BinaryOperator op, final Supplier supplierForEmpty) { final Supplier> supplier = () -> new OptHolder<>(op); final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner; final Function, T> finisher = a -> a.present ? a.value : supplierForEmpty.get(); return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param op * @return */ public static Collector reducingOrElseThrow(final BinaryOperator op) { return reducingOrElseThrow(op, noSuchElementExceptionSupplier); } /** * * @param * @param op * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrElseThrow(final BinaryOperator op, final Supplier exceptionSupplier) { final Supplier> supplier = () -> new OptHolder<>(op); final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner; final Function, T> finisher = a -> { if (a.present) { return a.value; } else { throw exceptionSupplier.get(); } }; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param identity * @param mapper * @param op * @return */ public static Collector reducing(final R identity, final Function mapper, final BinaryOperator op) { final BiConsumer, T> accumulator = (a, t) -> a.setValue(op.apply(a.value(), mapper.apply(t))); final BinaryOperator> combiner = (a, b) -> { a.setValue(op.apply(a.value(), b.value())); return a; }; @SuppressWarnings("rawtypes") final Function, R> finisher = (Function) Reducing_Finisher_0; return create(holderSupplier(identity), accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param mapper * @param op * @return */ @SuppressWarnings("rawtypes") public static Collector> reducing(final Function mapper, final BinaryOperator op) { final Supplier> supplier = () -> new MappingOptHolder<>(mapper, op); final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator_2; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner_2; final Function, Optional> finisher = (Function) Reducing_Finisher_2; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } private static Supplier> holderSupplier(final T identity) { return () -> Holder.of(identity); } private static class OptHolder implements Consumer { BinaryOperator op = null; T value = null; boolean present = false; OptHolder(final BinaryOperator op) { this.op = op; } @Override public void accept(final T t) { if (present) { value = op.apply(value, t); } else { value = t; present = true; } } } private static class MappingOptHolder implements Consumer { final Function mapper; final BinaryOperator op; U value = null; boolean present = false; MappingOptHolder(final Function mapper, final BinaryOperator op) { this.mapper = mapper; this.op = op; } @Override public void accept(final T t) { if (present) { value = op.apply(value, mapper.apply(t)); } else { value = mapper.apply(t); present = true; } } } /** * * @param * @param * @param mapper * @param op * @param supplierForEmpty * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrElseGet(final Function mapper, final BinaryOperator op, final Supplier supplierForEmpty) { final Supplier> supplier = () -> new MappingOptHolder<>(mapper, op); final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator_2; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner_2; final Function, R> finisher = a -> a.present ? a.value : supplierForEmpty.get(); return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param mapper * @param op * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrElseThrow(final Function mapper, final BinaryOperator op, final Supplier exceptionSupplier) { final Supplier> supplier = () -> new MappingOptHolder<>(mapper, op); final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator_2; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner_2; final Function, R> finisher = a -> { if (a.present) { return a.value; } else { throw exceptionSupplier.get(); } }; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param mapper * @param op * @return */ public static Collector reducingOrElseThrow(final Function mapper, final BinaryOperator op) { return reducingOrElseThrow(mapper, op, noSuchElementExceptionSupplier); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which computes a common prefix of input * {@code CharSequence} objects returning the result as {@code String}. For * empty input the empty {@code String} is returned. * *

* The returned {@code Collector} handles specially Unicode surrogate pairs: * the returned prefix may end with * * Unicode high-surrogate code unit only if it's not succeeded by * * Unicode low-surrogate code unit in any of the input sequences. * Normally, the ending high-surrogate code unit is removed from the prefix. * *

* This method returns a * short-circuiting * collector: it may not process all the elements if the common prefix * is empty. * * @return a {@code Collector} which computes a common prefix. */ public static Collector commonPrefix() { final Supplier> supplier = () -> Pair.of(null, -1); final BiConsumer, CharSequence> accumulator = (a, t) -> { if (a.right == -1) { a.left = t; a.right = N.len(t); } else if (a.right > 0) { // if (t.length() < a.right) { // a.right = t.length(); // } // // for (int i = 0, to = a.right; i < to; i++) { // if (a.left.charAt(i) != t.charAt(i)) { // if (i > 0 && Character.isHighSurrogate(t.charAt(i - 1)) // && (Character.isLowSurrogate(t.charAt(i)) || Character.isLowSurrogate(a.left.charAt(i)))) { // i--; // NOSONAR // } // // a.right = i; // // break; // } // } a.right = Strings.lengthOfCommonPrefix(a.left, t); a.left = N.len(t) < N.len(a.left) ? t : a.left; } }; final BinaryOperator> combiner = (a, b) -> { if (a.right == -1) { return b; } else if (b.right == -1) { return a; } accumulator.accept(a, b.right == 0 ? "" : b.left.subSequence(0, b.right)); return a; }; final Function, String> finisher = a -> a.left == null || a.right <= 0 ? "" : a.left.subSequence(0, a.right).toString(); return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * It's copied from StreamEx: StreamEx under Apache License v2 and may be modified. *
* * Returns a {@code Collector} which computes a common suffix of input * {@code CharSequence} objects returning the result as {@code String}. For * empty input the empty {@code String} is returned. * *

* The returned {@code Collector} handles specially Unicode surrogate pairs: * the returned suffix may start with * * Unicode low-surrogate code unit only if it's not preceded by * * Unicode high-surrogate code unit in any of the input sequences. * Normally, the starting low-surrogate code unit is removed from the suffix. * *

* This method returns a * short-circuiting * collector: it may not process all the elements if the common suffix * is empty. * * @return a {@code Collector} which computes a common suffix. */ public static Collector commonSuffix() { final Supplier> supplier = () -> Pair.of(null, -1); final BiConsumer, CharSequence> accumulator = (a, t) -> { if (a.right == -1) { a.left = t; a.right = t.length(); } else if (a.right > 0) { // int alen = a.left.length(); // int blen = t.length(); // // if (blen < a.right) { // a.right = blen; // } // // for (int i = 0, to = a.right; i < to; i++) { // if (a.left.charAt(alen - 1 - i) != t.charAt(blen - 1 - i)) { // if (i > 0 && Character.isLowSurrogate(t.charAt(blen - i)) // && (Character.isHighSurrogate(t.charAt(blen - 1 - i)) || Character.isHighSurrogate(a.left.charAt(alen - 1 - i)))) { // i--; // NOSONAR // } // // a.right = i; // // break; // } // } a.right = Strings.lengthOfCommonSuffix(a.left, t); a.left = N.len(t) < N.len(a.left) ? t : a.left; } }; final BinaryOperator> combiner = (a, b) -> { if (a.right == -1) { return b; } else if (b.right == -1) { return a; } final int bLen = b.left.length(); accumulator.accept(a, b.right == 0 ? "" : b.left.subSequence(bLen - b.right, bLen)); return a; }; final Function, String> finisher = a -> { if (a.left == null || a.right <= 0) { return ""; } final int aLen = a.left.length(); return a.left.subSequence(aLen - a.right, aLen).toString(); }; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param keyMapper * @return */ public static Collector>> groupingBy(final Function keyMapper) { final Collector> downstream = toList(); return groupingBy(keyMapper, downstream); } /** * * @param * @param * @param * @param keyMapper * @param mapFactory * @return */ public static >> Collector groupingBy(final Function keyMapper, final Supplier mapFactory) { final Collector> downstream = toList(); return groupingBy(keyMapper, downstream, mapFactory); } /** * * @param * @param * @param * @param * @param keyMapper * @param downstream * @return */ public static Collector> groupingBy(final Function keyMapper, final Collector downstream) { final Supplier> mapFactory = Suppliers.ofMap(); return groupingBy(keyMapper, downstream, mapFactory); } /** * * @param * @param * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return * @throws IllegalArgumentException */ public static > Collector groupingBy(final Function keyMapper, final Collector downstream, final Supplier mapFactory) throws IllegalArgumentException { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final Function mappingFunction = k -> downstreamSupplier.get(); final BiConsumer, T> accumulator = (m, t) -> { final K key = N.checkArgNotNull(keyMapper.apply(t), "element cannot be mapped to a null key"); final A container = computeIfAbsent(m, key, mappingFunction); downstreamAccumulator.accept(container, t); }; final BinaryOperator> combiner = Collectors.mapMerger(downstream.combiner()); @SuppressWarnings("unchecked") final Supplier> mangledFactory = (Supplier>) mapFactory; @SuppressWarnings("unchecked") final Function downstreamFinisher = (Function) downstream.finisher(); final BiFunction function = (k, v) -> downstreamFinisher.apply(v); final Function, M> finisher = intermediate -> { replaceAll(intermediate, function); return (M) intermediate; }; return create(mangledFactory, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param keyMapper * @return */ public static Collector>> groupingByConcurrent(final Function keyMapper) { final Collector> downstream = toList(); return groupingByConcurrent(keyMapper, downstream); } /** * * @param * @param * @param * @param keyMapper * @param mapFactory * @return */ public static >> Collector groupingByConcurrent(final Function keyMapper, final Supplier mapFactory) { final Collector> downstream = toList(); return groupingByConcurrent(keyMapper, downstream, mapFactory); } /** * * @param * @param * @param * @param * @param keyMapper * @param downstream * @return */ public static Collector> groupingByConcurrent(final Function keyMapper, final Collector downstream) { final Supplier> mapFactory = Suppliers.ofConcurrentMap(); return groupingByConcurrent(keyMapper, downstream, mapFactory); } /** * * @param * @param * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return * @throws IllegalArgumentException */ public static > Collector groupingByConcurrent(final Function keyMapper, final Collector downstream, final Supplier mapFactory) throws IllegalArgumentException { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final Function mappingFunction = k -> downstreamSupplier.get(); final BiConsumer, T> accumulator = (m, t) -> { final K key = N.checkArgNotNull(keyMapper.apply(t), "element cannot be mapped to a null key"); final A container = computeIfAbsent(m, key, mappingFunction); downstreamAccumulator.accept(container, t); }; final BinaryOperator> combiner = Collectors.mapMerger(downstream.combiner()); if (downstream.characteristics().contains(Characteristics.IDENTITY_FINISH)) { return create(mapFactory, (BiConsumer) accumulator, (BinaryOperator) combiner, CH_UNORDERED_ID); } else { @SuppressWarnings("unchecked") final Function downstreamFinisher = (Function) downstream.finisher(); final BiFunction function = (k, v) -> downstreamFinisher.apply(v); final Function, M> finisher = intermediate -> { replaceAll(intermediate, function); return (M) intermediate; }; return create((Supplier>) mapFactory, accumulator, combiner, finisher, CH_UNORDERED_NOID); } } /** * * @param * @param predicate * @return */ public static Collector>> partitioningBy(final Predicate predicate) { final Collector> downstream = toList(); return partitioningBy(predicate, downstream); } /** * * @param * @param * @param * @param predicate * @param downstream * @return */ public static Collector> partitioningBy(final Predicate predicate, final Collector downstream) { final Supplier> supplier = () -> { final Map map = N.newHashMap(2); map.put(true, downstream.supplier().get()); map.put(false, downstream.supplier().get()); return map; }; final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer, T> accumulator = (a, t) -> downstreamAccumulator .accept(predicate.test(t) ? a.get(Boolean.TRUE) : a.get(Boolean.FALSE), t); final BinaryOperator op = downstream.combiner(); final BinaryOperator> combiner = (a, b) -> { a.put(Boolean.TRUE, op.apply(a.get(Boolean.TRUE), b.get(Boolean.TRUE))); a.put(Boolean.FALSE, op.apply(a.get(Boolean.FALSE), b.get(Boolean.FALSE))); return a; }; final Function, Map> finisher = a -> { @SuppressWarnings("rawtypes") final Map result = (Map) a; result.put(Boolean.TRUE, downstream.finisher().apply((a.get(Boolean.TRUE)))); result.put(Boolean.FALSE, downstream.finisher().apply((a.get(Boolean.FALSE)))); return result; }; return create(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * @param * @param * @param keyMapper * @return */ public static Collector> countingBy(final Function keyMapper) { return countingBy(keyMapper, Suppliers.ofMap()); } /** * * @param * @param * @param * @param keyMapper * @param mapFactory * @return */ public static > Collector countingBy(final Function keyMapper, final Supplier mapFactory) { final Collector downstream = counting(); return groupingBy(keyMapper, downstream, mapFactory); } /** * * @param * @param * @param keyMapper * @return */ public static Collector> countingToIntBy(final Function keyMapper) { return countingToIntBy(keyMapper, Suppliers.ofMap()); } /** * * @param * @param * @param * @param keyMapper * @param mapFactory * @return */ public static > Collector countingToIntBy(final Function keyMapper, final Supplier mapFactory) { final Collector downstream = countingToInt(); return groupingBy(keyMapper, downstream, mapFactory); } /** * * @param * @param * @return */ public static Collector, ?, Map> toMap() { final Function, ? extends K> keyMapper = Fn.key(); final Function, ? extends V> valueMapper = Fn.value(); return toMap(keyMapper, valueMapper); } /** * * @param * @param * @param mergeFunction * @return */ public static Collector, ?, Map> toMap(final BinaryOperator mergeFunction) { final Function, ? extends K> keyMapper = Fn.key(); final Function, ? extends V> valueMapper = Fn.value(); return toMap(keyMapper, valueMapper, mergeFunction); } /** * * @param * @param * @param * @param mapFactory * @return */ public static > Collector, ?, M> toMap(final Supplier mapFactory) { final Function, ? extends K> keyMapper = Fn.key(); final Function, ? extends V> valueMapper = Fn.value(); return toMap(keyMapper, valueMapper, mapFactory); } /** * * @param * @param * @param * @param mergeFunction * @param mapFactory * @return */ public static > Collector, ?, M> toMap(final BinaryOperator mergeFunction, final Supplier mapFactory) { final Function, ? extends K> keyMapper = Fn.key(); final Function, ? extends V> valueMapper = Fn.value(); return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @return */ public static Collector> toMap(final Function keyMapper, final Function valueMapper) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toMap(keyMapper, valueMapper, mergeFunction); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return */ public static Collector> toMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction) { final Supplier> mapFactory = Suppliers.ofMap(); return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return */ public static > Collector toMap(final Function keyMapper, final Function valueMapper, final Supplier mapFactory) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return */ public static > Collector toMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> merge(map, keyMapper.apply(element), valueMapper.apply(element), mergeFunction); final BinaryOperator combiner = mapMerger(mergeFunction); return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param * @return */ public static Collector, ?, ImmutableMap> toImmutableMap() { final Collector, ?, Map> downstream = toMap(); @SuppressWarnings("rawtypes") final Function, ImmutableMap> finisher = (Function) ImmutableMap_Finisher; return collectingAndThen(downstream, finisher); } /** * * @param * @param * @param mergeFunction * @return */ public static Collector, ?, ImmutableMap> toImmutableMap(final BinaryOperator mergeFunction) { final Collector, ?, Map> downstream = toMap(mergeFunction); @SuppressWarnings("rawtypes") final Function, ImmutableMap> finisher = (Function) ImmutableMap_Finisher; return collectingAndThen(downstream, finisher); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @return */ public static Collector> toImmutableMap(final Function keyMapper, final Function valueMapper) { final Collector> downstream = toMap(keyMapper, valueMapper); @SuppressWarnings("rawtypes") final Function, ImmutableMap> finisher = (Function) ImmutableMap_Finisher; return collectingAndThen(downstream, finisher); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return */ public static Collector> toImmutableMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction) { final Collector> downstream = toMap(keyMapper, valueMapper, mergeFunction); @SuppressWarnings("rawtypes") final Function, ImmutableMap> finisher = (Function) ImmutableMap_Finisher; return collectingAndThen(downstream, finisher); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @return * @see java.util.stream.Collectors#toUnmodifiableMap(Function, Function) */ public static Collector> toUnmodifiableMap(final Function keyMapper, final Function valueMapper) { return java.util.stream.Collectors.toUnmodifiableMap(keyMapper, valueMapper); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @see java.util.stream.Collectors#toUnmodifiableMap(Function, Function, BinaryOperator) */ public static Collector> toUnmodifiableMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction) { return java.util.stream.Collectors.toUnmodifiableMap(keyMapper, valueMapper, mergeFunction); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @return * @see #toMap(Function, Function) */ public static Collector> toLinkedHashMap(final Function keyMapper, final Function valueMapper) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toLinkedHashMap(keyMapper, valueMapper, mergeFunction); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @see #toMap(Function, Function, BinaryOperator) */ public static Collector> toLinkedHashMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction) { final Supplier> mapFactory = Suppliers.ofLinkedHashMap(); return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @return */ public static Collector> toConcurrentMap(final Function keyMapper, final Function valueMapper) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toConcurrentMap(keyMapper, valueMapper, mergeFunction); } /** * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return */ public static > Collector toConcurrentMap(final Function keyMapper, final Function valueMapper, final Supplier mapFactory) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toConcurrentMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return */ public static Collector> toConcurrentMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction) { final Supplier> mapFactory = Suppliers.ofConcurrentMap(); return toConcurrentMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return */ public static > Collector toConcurrentMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> merge(map, keyMapper.apply(element), valueMapper.apply(element), mergeFunction); final BinaryOperator combiner = concurrentMapMerger(mergeFunction); return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @return */ public static Collector> toBiMap(final Function keyMapper, final Function valueMapper) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toBiMap(keyMapper, valueMapper, mergeFunction); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return */ public static Collector> toBiMap(final Function keyMapper, final Function valueMapper, final Supplier> mapFactory) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toBiMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return */ public static Collector> toBiMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction) { final Supplier> mapFactory = Suppliers.ofBiMap(); return toBiMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return */ public static Collector> toBiMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, final Supplier> mapFactory) { return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } /** * * @param * @param * @return */ @SuppressWarnings("rawtypes") public static Collector, ?, ListMultimap> toMultimap() { final Function, ? extends K> keyMapper = (Function) Fn.key(); final Function, ? extends V> valueMapper = (Function) Fn.value(); return toMultimap(keyMapper, valueMapper); } /** * * @param * @param * @param * @param * @param mapFactory * @return */ @SuppressWarnings("rawtypes") public static , M extends Multimap> Collector, ?, M> toMultimap( final Supplier mapFactory) { final Function, ? extends K> keyMapper = (Function) Fn.key(); final Function, ? extends V> valueMapper = (Function) Fn.value(); return toMultimap(keyMapper, valueMapper, mapFactory); } /** * * @param * @param * @param keyMapper * @return */ public static Collector> toMultimap(final Function keyMapper) { final Function valueMapper = Fn.identity(); return toMultimap(keyMapper, valueMapper); } /** * * @param * @param * @param * @param * @param keyMapper * @param mapFactory * @return */ public static , M extends Multimap> Collector toMultimap(final Function keyMapper, final Supplier mapFactory) { final Function valueMapper = Fn.identity(); return toMultimap(keyMapper, valueMapper, mapFactory); } /** * * @param * @param * @param * @param keyMapper * @param valueMapper * @return */ public static Collector> toMultimap(final Function keyMapper, final Function valueMapper) { final Supplier> mapFactory = Suppliers.ofListMultimap(); return toMultimap(keyMapper, valueMapper, mapFactory); } /** * * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return */ public static , M extends Multimap> Collector toMultimap( final Function keyMapper, final Function valueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> map.put(keyMapper.apply(element), valueMapper.apply(element)); final BinaryOperator combiner = Collectors.multimapMerger(); return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param * @param * @param keyMapper * @param flatValueExtractor * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatMappingValueToMultimap(final Function keyMapper, final Function> flatValueExtractor) { return flatMappingValueToMultimap(keyMapper, flatValueExtractor, Suppliers.ofListMultimap()); } /** * * @param * @param * @param * @param * @param * @param keyMapper * @param flatValueExtractor * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatMappingValueToMultimap( final Function keyMapper, final Function> flatValueExtractor, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final K key = keyMapper.apply(element); try (Stream stream = flatValueExtractor.apply(element)) { if (stream.isParallel()) { stream.sequential().forEach(value -> map.put(key, value)); } else { stream.forEach(value -> map.put(key, value)); } } }; final BinaryOperator combiner = Collectors.multimapMerger(); return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param * @param * @param keyMapper * @param flatValueExtractor * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatmappingValueToMultimap(final Function keyMapper, // NOSONAR final Function> flatValueExtractor) { return flatmappingValueToMultimap(keyMapper, flatValueExtractor, Suppliers.ofListMultimap()); } /** * * @param * @param * @param * @param * @param * @param keyMapper * @param flatValueExtractor * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatmappingValueToMultimap( // NOSONAR final Function keyMapper, final Function> flatValueExtractor, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final K key = keyMapper.apply(element); final Collection values = flatValueExtractor.apply(element); if (N.notEmpty(values)) { for (final V value : values) { map.put(key, value); } } }; final BinaryOperator combiner = Collectors.multimapMerger(); return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param * @param * @param flatKeyExtractor * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatMappingKeyToMultimap(final Function> flatKeyExtractor, final Function valueMapper) { return flatMappingKeyToMultimap(flatKeyExtractor, valueMapper, Suppliers.ofListMultimap()); } /** * * @param * @param * @param * @param * @param * @param flatKeyExtractor * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatMappingKeyToMultimap( final Function> flatKeyExtractor, final Function valueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final V value = valueMapper.apply(element); try (Stream stream = flatKeyExtractor.apply(element)) { if (stream.isParallel()) { stream.sequential().forEach(key -> map.put(key, value)); } else { stream.forEach(key -> map.put(key, value)); } } }; final BinaryOperator combiner = Collectors.multimapMerger(); return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * @param * @param * @param * @param flatKeyExtractor * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatmappingKeyToMultimap( // NOSONAR final Function> flatKeyExtractor, final Function valueMapper) { return flatmappingKeyToMultimap(flatKeyExtractor, valueMapper, Suppliers.ofListMultimap()); } /** * * @param * @param * @param * @param * @param * @param flatKeyExtractor * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatmappingKeyToMultimap( // NOSONAR final Function> flatKeyExtractor, final Function valueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final V value = valueMapper.apply(element); final Collection keys = flatKeyExtractor.apply(element); if (N.notEmpty(keys)) { for (final K key : keys) { map.put(key, value); } } }; final BinaryOperator combiner = Collectors.multimapMerger(); return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } static void replaceAll(final Map map, final BiFunction function) { N.checkArgNotNull(function); try { for (final Map.Entry entry : map.entrySet()) { entry.setValue(function.apply(entry.getKey(), entry.getValue())); } } catch (final IllegalStateException ise) { throw new ConcurrentModificationException(ise); } } private static V computeIfAbsent(final Map map, final K key, final Function mappingFunction) { N.checkArgNotNull(mappingFunction); V v = null; if ((v = map.get(key)) == null) { // NOSONAR V newValue = null; if ((newValue = mappingFunction.apply(key)) != null) { map.put(key, newValue); return newValue; } } return v; } private static > BinaryOperator mapMerger(final BinaryOperator mergeFunction) { N.checkArgNotNull(mergeFunction); return (m1, m2) -> { for (final Map.Entry e : m2.entrySet()) { final V oldValue = m1.get(e.getKey()); if (oldValue == null && !m1.containsKey(e.getKey())) { m1.put(e.getKey(), e.getValue()); } else { m1.put(e.getKey(), mergeFunction.apply(oldValue, e.getValue())); } } return m1; }; } private static > BinaryOperator concurrentMapMerger(final BinaryOperator mergeFunction) { N.checkArgNotNull(mergeFunction); return (m1, m2) -> { for (final Map.Entry e : m2.entrySet()) { final V oldValue = m1.get(e.getKey()); if (oldValue == null && !m1.containsKey(e.getKey())) { m1.put(e.getKey(), e.getValue()); } else { m1.put(e.getKey(), mergeFunction.apply(oldValue, e.getValue())); } } return m1; }; } private static , M extends Multimap> BinaryOperator multimapMerger() { return (m1, m2) -> { K key = null; V value = null; for (final Map.Entry e : m2.entrySet()) { N.checkArgNotNull(e.getValue()); key = e.getKey(); value = e.getValue(); if (N.notEmpty(value)) { final V oldValue = m1.get(key); if (oldValue == null) { m1.putMany(key, value); } else { oldValue.addAll(value); } } } return m1; }; } static void merge(final Map map, final K key, final V value, final BiFunction remappingFunction) { N.checkArgNotNull(remappingFunction); final V oldValue = map.get(key); if (oldValue == null && !map.containsKey(key)) { map.put(key, value); } else { map.put(key, remappingFunction.apply(oldValue, value)); } } // // Too many/much? // /** // * // * // * @param // * @param // * @param // * @param keyMapper // * @param flatValueExtractor // * @return // * @see Collectors#toMultimap(Function, Function) // */ // public static Collector> flattMappingValueToMultimap(final Function keyMapper, // final Function> flatValueExtractor) { // return flattMappingValueToMultimap(keyMapper, flatValueExtractor, Suppliers. ofListMultimap()); // } // // /** // * // * // * @param // * @param // * @param // * @param // * @param // * @param keyMapper // * @param flatValueExtractor // * @param mapFactory // * @return // * @see Collectors#toMultimap(Function, Function, Supplier) // */ // public static , M extends Multimap> Collector flattMappingValueToMultimap( // final Function keyMapper, final Function> flatValueExtractor, // final Supplier mapFactory) { // // final BiConsumer accumulator = (map, element) -> { // final K key = keyMapper.apply(element); // // try (java.util.stream.Stream stream = flatValueExtractor.apply(element)) { // if (stream.isParallel()) { // stream.sequential().forEach(value -> map.put(key, value)); // } else { // stream.forEach(value -> map.put(key, value)); // } // } // }; // // final BinaryOperator combiner = Collectors. multimapMerger(); // // return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); // } // // /** // * // * // * @param // * @param // * @param // * @param flatKeyExtractor // * @param valueMapper // * @return // * @see Collectors#toMultimap(Function, Function) // */ // public static Collector> flattMappingKeyToMultimap( // final Function> flatKeyExtractor, final Function valueMapper) { // return flattMappingKeyToMultimap(flatKeyExtractor, valueMapper, Suppliers. ofListMultimap()); // } // // /** // * // * // * @param // * @param // * @param // * @param // * @param // * @param flatKeyExtractor // * @param valueMapper // * @param mapFactory // * @return // * @see Collectors#toMultimap(Function, Function, Supplier) // */ // public static , M extends Multimap> Collector flattMappingKeyToMultimap( // final Function> flatKeyExtractor, final Function valueMapper, // final Supplier mapFactory) { // // final BiConsumer accumulator = (map, element) -> { // final V value = valueMapper.apply(element); // // try (java.util.stream.Stream stream = flatKeyExtractor.apply(element)) { // if (stream.isParallel()) { // stream.sequential().forEach(key -> map.put(key, value)); // } else { // stream.forEach(key -> map.put(key, value)); // } // } // }; // // final BinaryOperator combiner = Collectors. multimapMerger(); // // return create(mapFactory, accumulator, combiner, CH_UNORDERED_ID); // } /** * * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param merger * @return */ public static Collector teeing(final Collector downstream1, final Collector downstream2, final BiFunction merger) { return MoreCollectors.combine(downstream1, downstream2, merger); } public static final class MoreCollectors extends Collectors { MoreCollectors() { // for extension. } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> summingInt(final ToIntFunction mapper1, final ToIntFunction mapper2) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper1.applyAsInt(t); a[1] += mapper2.applyAsInt(t); }; return create(SummingInt_Supplier_2, accumulator, SummingInt_Combiner_2, SummingInt_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> summingInt(final ToIntFunction mapper1, final ToIntFunction mapper2, final ToIntFunction mapper3) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper1.applyAsInt(t); a[1] += mapper2.applyAsInt(t); a[2] += mapper3.applyAsInt(t); }; return create(SummingInt_Supplier_3, accumulator, SummingInt_Combiner_3, SummingInt_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> summingIntToLong(final ToIntFunction mapper1, final ToIntFunction mapper2) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper1.applyAsInt(t); a[1] += mapper2.applyAsInt(t); }; return create(SummingIntToLong_Supplier_2, accumulator, SummingIntToLong_Combiner_2, SummingIntToLong_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> summingIntToLong(final ToIntFunction mapper1, final ToIntFunction mapper2, final ToIntFunction mapper3) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper1.applyAsInt(t); a[1] += mapper2.applyAsInt(t); a[2] += mapper3.applyAsInt(t); }; return create(SummingIntToLong_Supplier_3, accumulator, SummingIntToLong_Combiner_3, SummingIntToLong_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> summingLong(final ToLongFunction mapper1, final ToLongFunction mapper2) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper1.applyAsLong(t); a[1] += mapper2.applyAsLong(t); }; return create(SummingLong_Supplier_2, accumulator, SummingLong_Combiner_2, SummingLong_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> summingLong(final ToLongFunction mapper1, final ToLongFunction mapper2, final ToLongFunction mapper3) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper1.applyAsLong(t); a[1] += mapper2.applyAsLong(t); a[2] += mapper3.applyAsLong(t); }; return create(SummingLong_Supplier_3, accumulator, SummingLong_Combiner_3, SummingLong_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> summingDouble(final ToDoubleFunction mapper1, final ToDoubleFunction mapper2) { final BiConsumer accumulator = (a, t) -> { a[0].add(mapper1.applyAsDouble(t)); a[1].add(mapper2.applyAsDouble(t)); }; return create(SummingDouble_Supplier_2, accumulator, SummingDouble_Combiner_2, SummingDouble_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> summingDouble(final ToDoubleFunction mapper1, final ToDoubleFunction mapper2, final ToDoubleFunction mapper3) { final BiConsumer accumulator = (a, t) -> { a[0].add(mapper1.applyAsDouble(t)); a[1].add(mapper2.applyAsDouble(t)); a[2].add(mapper3.applyAsDouble(t)); }; return create(SummingDouble_Supplier_3, accumulator, SummingDouble_Combiner_3, SummingDouble_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> summingBigInteger(final Function mapper1, final Function mapper2) { final BiConsumer accumulator = (a, t) -> { a[0] = a[0].add(mapper1.apply(t)); a[1] = a[1].add(mapper2.apply(t)); }; return create(SummingBigInteger_Supplier_2, accumulator, SummingBigInteger_Combiner_2, SummingBigInteger_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> summingBigInteger(final Function mapper1, final Function mapper2, final Function mapper3) { final BiConsumer accumulator = (a, t) -> { a[0] = a[0].add(mapper1.apply(t)); a[1] = a[1].add(mapper2.apply(t)); a[2] = a[2].add(mapper3.apply(t)); }; return create(SummingBigInteger_Supplier_3, accumulator, SummingBigInteger_Combiner_3, SummingBigInteger_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> summingBigDecimal(final Function mapper1, final Function mapper2) { final BiConsumer accumulator = (a, t) -> { a[0] = a[0].add(mapper1.apply(t)); a[1] = a[1].add(mapper2.apply(t)); }; return create(SummingBigDecimal_Supplier_2, accumulator, SummingBigDecimal_Combiner_2, SummingBigDecimal_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> summingBigDecimal(final Function mapper1, final Function mapper2, final Function mapper3) { final BiConsumer accumulator = (a, t) -> { a[0] = a[0].add(mapper1.apply(t)); a[1] = a[1].add(mapper2.apply(t)); a[2] = a[2].add(mapper3.apply(t)); }; return create(SummingBigDecimal_Supplier_3, accumulator, SummingBigDecimal_Combiner_3, SummingBigDecimal_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> averagingInt(final ToIntFunction mapper1, final ToIntFunction mapper2) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] += mapper1.applyAsInt(t); a.left[1] += mapper2.applyAsInt(t); a.right[0] += 1; a.right[1] += 1; }; return create(AveragingInt_Supplier_2, accumulator, AveragingInt_Combiner_2, AveragingInt_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> averagingInt(final ToIntFunction mapper1, final ToIntFunction mapper2, final ToIntFunction mapper3) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] += mapper1.applyAsInt(t); a.left[1] += mapper2.applyAsInt(t); a.left[2] += mapper3.applyAsInt(t); a.right[0] += 1; a.right[1] += 1; a.right[2] += 1; }; return create(AveragingInt_Supplier_3, accumulator, AveragingInt_Combiner_3, AveragingInt_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> averagingLong(final ToLongFunction mapper1, final ToLongFunction mapper2) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] += mapper1.applyAsLong(t); a.left[1] += mapper2.applyAsLong(t); a.right[0] += 1; a.right[1] += 1; }; return create(AveragingLong_Supplier_2, accumulator, AveragingLong_Combiner_2, AveragingLong_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> averagingLong(final ToLongFunction mapper1, final ToLongFunction mapper2, final ToLongFunction mapper3) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] += mapper1.applyAsLong(t); a.left[1] += mapper2.applyAsLong(t); a.left[2] += mapper3.applyAsLong(t); a.right[0] += 1; a.right[1] += 1; a.right[2] += 1; }; return create(AveragingLong_Supplier_3, accumulator, AveragingLong_Combiner_3, AveragingLong_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> averagingDouble(final ToDoubleFunction mapper1, final ToDoubleFunction mapper2) { final BiConsumer accumulator = (a, t) -> { a[0].add(mapper1.applyAsDouble(t)); a[1].add(mapper2.applyAsDouble(t)); }; return create(AveragingDouble_Supplier_2, accumulator, AveragingDouble_Combiner_2, AveragingDouble_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> averagingDouble(final ToDoubleFunction mapper1, final ToDoubleFunction mapper2, final ToDoubleFunction mapper3) { final BiConsumer accumulator = (a, t) -> { a[0].add(mapper1.applyAsDouble(t)); a[1].add(mapper2.applyAsDouble(t)); a[2].add(mapper3.applyAsDouble(t)); }; return create(AveragingDouble_Supplier_3, accumulator, AveragingDouble_Combiner_3, AveragingDouble_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> averagingBigInteger(final Function mapper1, final Function mapper2) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] = a.left[0].add(mapper1.apply(t)); a.left[1] = a.left[1].add(mapper2.apply(t)); a.right[0] += 1; a.right[1] += 1; }; return create(AveragingBigInteger_Supplier_2, accumulator, AveragingBigInteger_Combiner_2, AveragingBigInteger_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> averagingBigInteger(final Function mapper1, final Function mapper2, final Function mapper3) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] = a.left[0].add(mapper1.apply(t)); a.left[1] = a.left[1].add(mapper2.apply(t)); a.left[2] = a.left[2].add(mapper3.apply(t)); a.right[0] += 1; a.right[1] += 1; a.right[2] += 1; }; return create(AveragingBigInteger_Supplier_3, accumulator, AveragingBigInteger_Combiner_3, AveragingBigInteger_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @return */ public static Collector> averagingBigDecimal(final Function mapper1, final Function mapper2) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] = a.left[0].add(mapper1.apply(t)); a.left[1] = a.left[1].add(mapper2.apply(t)); a.right[0] += 1; a.right[1] += 1; }; return create(AveragingBigDecimal_Supplier_2, accumulator, AveragingBigDecimal_Combiner_2, AveragingBigDecimal_Finisher_2, CH_UNORDERED_NOID); } /** * * @param * @param mapper1 * @param mapper2 * @param mapper3 * @return */ public static Collector> averagingBigDecimal(final Function mapper1, final Function mapper2, final Function mapper3) { final BiConsumer, T> accumulator = (a, t) -> { a.left[0] = a.left[0].add(mapper1.apply(t)); a.left[1] = a.left[1].add(mapper2.apply(t)); a.left[2] = a.left[2].add(mapper3.apply(t)); a.right[0] += 1; a.right[1] += 1; a.right[2] += 1; }; return create(AveragingBigDecimal_Supplier_3, accumulator, AveragingBigDecimal_Combiner_3, AveragingBigDecimal_Finisher_3, CH_UNORDERED_NOID); } /** * * @param * @param * @param * @param downstream1 * @param downstream2 * @return */ public static Collector> combine(final Collector downstream1, final Collector downstream2) { return combine(downstream1, downstream2, Tuple::of); } /** * * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param downstream3 * @return */ public static Collector> combine(final Collector downstream1, final Collector downstream2, final Collector downstream3) { return combine(downstream1, downstream2, downstream3, Tuple::of); } /** * * @param * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param downstream3 * @param downstream4 * @return */ public static Collector> combine(final Collector downstream1, final Collector downstream2, final Collector downstream3, final Collector downstream4) { return combine(downstream1, downstream2, downstream3, downstream4, Tuple::of); } /** * * @param * @param * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param downstream3 * @param downstream4 * @param downstream5 * @return * @throws IllegalArgumentException */ public static Collector> combine(final Collector downstream1, final Collector downstream2, final Collector downstream3, final Collector downstream4, final Collector downstream5) throws IllegalArgumentException { N.checkArgNotNull(downstream1, "downstream1"); //NOSONAR N.checkArgNotNull(downstream2, "downstream2"); //NOSONAR N.checkArgNotNull(downstream3, "downstream3"); //NOSONAR N.checkArgNotNull(downstream4, "downstream4"); //NOSONAR N.checkArgNotNull(downstream5, "downstream5"); //NOSONAR final List> downstreams = Array.asList(downstream1, downstream2, downstream3, downstream4, downstream5); final Function> finalMerger = a -> Tuple.of((R1) a[0], (R2) a[1], (R3) a[2], (R4) a[3], (R5) a[4]); return combine(downstreams, finalMerger); } /** * * @param * @param * @param * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param downstream3 * @param downstream4 * @param downstream5 * @param downstream6 * @return * @throws IllegalArgumentException */ public static Collector> combine(final Collector downstream1, final Collector downstream2, final Collector downstream3, final Collector downstream4, final Collector downstream5, final Collector downstream6) throws IllegalArgumentException { N.checkArgNotNull(downstream1, cs.downstream1); N.checkArgNotNull(downstream2, cs.downstream2); N.checkArgNotNull(downstream3, cs.downstream3); N.checkArgNotNull(downstream4, cs.downstream4); N.checkArgNotNull(downstream5, cs.downstream5); N.checkArgNotNull(downstream6, cs.downstream6); final List> downstreams = Array.asList(downstream1, downstream2, downstream3, downstream4, downstream5, downstream6); final Function> finalMerger = a -> Tuple.of((R1) a[0], (R2) a[1], (R3) a[2], (R4) a[3], (R5) a[4], (R6) a[5]); return combine(downstreams, finalMerger); } /** * * @param * @param * @param * @param * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param downstream3 * @param downstream4 * @param downstream5 * @param downstream6 * @param downstream7 * @return * @throws IllegalArgumentException */ public static Collector> combine(final Collector downstream1, final Collector downstream2, final Collector downstream3, final Collector downstream4, final Collector downstream5, final Collector downstream6, final Collector downstream7) throws IllegalArgumentException { N.checkArgNotNull(downstream1, cs.downstream1); N.checkArgNotNull(downstream2, cs.downstream2); N.checkArgNotNull(downstream3, cs.downstream3); N.checkArgNotNull(downstream4, cs.downstream4); N.checkArgNotNull(downstream5, cs.downstream5); N.checkArgNotNull(downstream6, cs.downstream6); N.checkArgNotNull(downstream7, cs.downstream7); final List> downstreams = Array.asList(downstream1, downstream2, downstream3, downstream4, downstream5, downstream6, downstream7); final Function> finalMerger = a -> Tuple.of((R1) a[0], (R2) a[1], (R3) a[2], (R4) a[3], (R5) a[4], (R6) a[5], (R7) a[6]); return combine(downstreams, finalMerger); } /** * * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param merger * @return * @throws IllegalArgumentException */ @SuppressWarnings("rawtypes") public static Collector combine(final Collector downstream1, final Collector downstream2, final BiFunction merger) throws IllegalArgumentException { N.checkArgNotNull(downstream1, cs.downstream1); N.checkArgNotNull(downstream2, cs.downstream2); N.checkArgNotNull(merger, "merger"); //NOSONAR final Supplier c1supplier = (Supplier) downstream1.supplier(); final Supplier c2Supplier = (Supplier) downstream2.supplier(); final BiConsumer c1Accumulator = (BiConsumer) downstream1.accumulator(); final BiConsumer c2Accumulator = (BiConsumer) downstream2.accumulator(); final BinaryOperator c1Combiner = (BinaryOperator) downstream1.combiner(); final BinaryOperator c2Combiner = (BinaryOperator) downstream2.combiner(); final Function c1Finisher = (Function) downstream1.finisher(); final Function c2Finisher = (Function) downstream2.finisher(); final Supplier> supplier = () -> Tuple.of(c1supplier.get(), c2Supplier.get()); final BiConsumer, T> accumulator = (acct, e) -> { c1Accumulator.accept(acct._1, e); c2Accumulator.accept(acct._2, e); }; final BinaryOperator> combiner = (t, u) -> Tuple.of(c1Combiner.apply(t._1, u._1), c2Combiner.apply(t._2, u._2)); final Function, R> finisher = t -> merger.apply(c1Finisher.apply(t._1), c2Finisher.apply(t._2)); final List common = N.intersection(downstream1.characteristics(), downstream2.characteristics()); common.remove(Characteristics.IDENTITY_FINISH); final Set characteristics = N.isEmpty(common) ? N.emptySet() : N.newHashSet(common); return create(supplier, accumulator, combiner, finisher, characteristics); } /** * * @param * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param downstream3 * @param merger * @return * @throws IllegalArgumentException */ @SuppressWarnings("rawtypes") public static Collector combine(final Collector downstream1, final Collector downstream2, final Collector downstream3, final TriFunction merger) throws IllegalArgumentException { N.checkArgNotNull(downstream1, cs.downstream1); N.checkArgNotNull(downstream2, cs.downstream2); N.checkArgNotNull(downstream3, cs.downstream3); N.checkArgNotNull(merger, cs.merger); final Supplier c1supplier = (Supplier) downstream1.supplier(); final Supplier c2Supplier = (Supplier) downstream2.supplier(); final Supplier c3Supplier = (Supplier) downstream3.supplier(); final BiConsumer c1Accumulator = (BiConsumer) downstream1.accumulator(); final BiConsumer c2Accumulator = (BiConsumer) downstream2.accumulator(); final BiConsumer c3Accumulator = (BiConsumer) downstream3.accumulator(); final BinaryOperator c1Combiner = (BinaryOperator) downstream1.combiner(); final BinaryOperator c2Combiner = (BinaryOperator) downstream2.combiner(); final BinaryOperator c3Combiner = (BinaryOperator) downstream3.combiner(); final Function c1Finisher = (Function) downstream1.finisher(); final Function c2Finisher = (Function) downstream2.finisher(); final Function c3Finisher = (Function) downstream3.finisher(); final Supplier> supplier = () -> Tuple.of(c1supplier.get(), c2Supplier.get(), c3Supplier.get()); final BiConsumer, T> accumulator = (acct, e) -> { c1Accumulator.accept(acct._1, e); c2Accumulator.accept(acct._2, e); c3Accumulator.accept(acct._3, e); }; final BinaryOperator> combiner = (t, u) -> Tuple.of(c1Combiner.apply(t._1, u._1), c2Combiner.apply(t._2, u._2), c3Combiner.apply(t._3, u._3)); final Function, R> finisher = t -> merger.apply(c1Finisher.apply(t._1), c2Finisher.apply(t._2), c3Finisher.apply(t._3)); final List common = N.intersection(downstream1.characteristics(), downstream2.characteristics()); common.remove(Characteristics.IDENTITY_FINISH); final Set characteristics = N.isEmpty(common) ? N.emptySet() : N.newHashSet(common); return create(supplier, accumulator, combiner, finisher, characteristics); } /** * * @param * @param * @param * @param * @param * @param * @param downstream1 * @param downstream2 * @param downstream3 * @param downstream4 * @param merger * @return * @throws IllegalArgumentException */ public static Collector combine(final Collector downstream1, final Collector downstream2, final Collector downstream3, final Collector downstream4, final QuadFunction merger) throws IllegalArgumentException { N.checkArgNotNull(downstream1, cs.downstream1); N.checkArgNotNull(downstream2, cs.downstream2); N.checkArgNotNull(downstream3, cs.downstream3); N.checkArgNotNull(downstream4, cs.downstream4); N.checkArgNotNull(merger, cs.merger); final List> downstreams = Array.asList(downstream1, downstream2, downstream3, downstream4); final Function finalMerger = a -> merger.apply((R1) a[0], (R2) a[1], (R3) a[2], (R4) a[3]); return combine(downstreams, finalMerger); } /** * * @param * @param * @param downstreams * @param merger * @return */ public static Collector combine(final Collection> downstreams, final Function merger) { //NOSONAR N.checkArgument(N.notEmpty(downstreams), "The specified 'collectors' can't be null or empty"); N.checkArgNotNull(merger, cs.merger); final int size = downstreams.size(); final Supplier[] suppliers = downstreams.stream().map(Collector::supplier).toArray(i -> new Supplier[size]); final BiConsumer[] accumulators = downstreams.stream().map(Collector::accumulator).toArray(i -> new BiConsumer[size]); final BinaryOperator[] combiners = downstreams.stream().map(Collector::combiner).toArray(i -> new BinaryOperator[size]); final Function[] finishers = downstreams.stream().map(Collector::finisher).toArray(i -> new Function[size]); final Supplier supplier = () -> { final Object[] a = new Object[size]; for (int i = 0; i < size; i++) { a[i] = suppliers[i].get(); } return a; }; final BiConsumer accumulator = (a, e) -> { for (int i = 0; i < size; i++) { accumulators[i].accept(a[i], e); } }; final BinaryOperator combiner = (a, b) -> { for (int i = 0; i < size; i++) { a[i] = combiners[i].apply(a[i], b[i]); } return a; }; final Function finisher = a -> { for (int i = 0; i < size; i++) { a[i] = finishers[i].apply(a[i]); } return merger.apply(a); }; final Collection common = N.intersection(downstreams.stream().map(Collector::characteristics).filter(N::notEmpty).toList()); common.remove(Characteristics.IDENTITY_FINISH); final Set characteristics = N.isEmpty(common) ? N.emptySet() : N.newHashSet(common); return create(supplier, accumulator, combiner, finisher, characteristics); } /** * * @param * @return */ public static Collector toDataSet() { return toDataSet(null); } /** * * @param * @param columnNames * @return */ public static Collector toDataSet(final List columnNames) { @SuppressWarnings("rawtypes") final Collector, List> collector = (Collector) Collectors.toList(); final Function, DataSet> finisher = t -> N.newDataSet(columnNames, t); return create(collector.supplier(), collector.accumulator(), collector.combiner(), finisher, Collectors.CH_NOID); } } }