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.

There is a newer version: 5.2.4
Show 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
 *
 * http://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 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.EnumSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
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.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.Comparators;
import com.landawn.abacus.util.DataSet;
import com.landawn.abacus.util.DoubleList;
import com.landawn.abacus.util.DoubleSummaryStatistics;
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.IntSummaryStatistics;
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.LongMultiset;
import com.landawn.abacus.util.LongSummaryStatistics;
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.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.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
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;

/**
 *
 * @see {@code java.util.stream.Collectors}
 *
 */
public abstract class Collectors {
    static final Object NONE = new Object(); //NOSONAR

    /**
     * @deprecated
     */
    @Deprecated
    static final Set CH_CONCURRENT_ID = Collections
            .unmodifiableSet(EnumSet.of(Characteristics.CONCURRENT, Characteristics.UNORDERED, Characteristics.IDENTITY_FINISH));
    /**
     * @deprecated
     */
    @Deprecated
    static final Set CH_CONCURRENT_NOID = Collections.unmodifiableSet(EnumSet.of(Characteristics.CONCURRENT, Characteristics.UNORDERED));

    static final Set CH_UNORDERED_ID = Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED, Characteristics.IDENTITY_FINISH));
    static final Set CH_UNORDERED_NOID = Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));

    static final Set CH_ID = Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
    static final Set CH_NOID = Collections.emptySet();

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

    @SuppressWarnings("deprecation")
    static final Function, ImmutableList> ImmutableList_Finisher = ImmutableList::wrap;

    @SuppressWarnings("deprecation")
    static final Function, ImmutableSet> ImmutableSet_Finisher = ImmutableSet::wrap;

    @SuppressWarnings("deprecation")
    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, Object> LongMultiset_Accumulator = LongMultiset::add;

    static final BinaryOperator> LongMultiset_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 Function Counting_Accumulator = t -> 1L;

    static final BinaryOperator Counting_Combiner = (a, b) -> a.longValue() + b.longValue();

    static final Function CountingInt_Accumulator = t -> 1;

    static final BinaryOperator CountingInt_Combiner = (a, b) -> a.intValue() + b.intValue();

    static final Supplier SummingInt_Supplier = () -> new long[1];
    static final Supplier SummingInt_Supplier_2 = () -> new long[2];
    static final Supplier SummingInt_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 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 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();
        }

        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();
        }

        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();
        }

        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();
        }

        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();
        }

        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();
        }

        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();
        }

        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();
        }

        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();
        }

        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;
    };

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

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

    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])));

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

        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])));
    };

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

        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;
    };

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

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

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

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

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

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

        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;
        }
    }

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

        return new CollectorImpl<>(collectionFactory, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @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 
     */
    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 
     */
    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  
     * @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();

                        for (int i = 0; i < n; i++) {
                            a.add(iter.next());
                        }
                    }
                }
            }

            return a;
        };

        return new CollectorImpl<>(collectionFactory, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @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  
     * @return 
     */
    public static  Collector> toMultiset() {
        final Supplier> supplier = Suppliers.ofMultiset();

        return toMultiset(supplier);
    }

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

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID);
    }

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

        return toLongMultiset(supplier);
    }

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

        return new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toBooleanList() {
        final Supplier supplier = Suppliers.ofBooleanList();
        final BiConsumer accumulator = BooleanList_Accumulator;
        final BinaryOperator combiner = BooleanList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toCharList() {
        final Supplier supplier = Suppliers.ofCharList();
        final BiConsumer accumulator = CharList_Accumulator;
        final BinaryOperator combiner = CharList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toByteList() {
        final Supplier supplier = Suppliers.ofByteList();
        final BiConsumer accumulator = ByteList_Accumulator;
        final BinaryOperator combiner = ByteList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toShortList() {
        final Supplier supplier = Suppliers.ofShortList();
        final BiConsumer accumulator = ShortList_Accumulator;
        final BinaryOperator combiner = ShortList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toIntList() {
        final Supplier supplier = Suppliers.ofIntList();
        final BiConsumer accumulator = IntList_Accumulator;
        final BinaryOperator combiner = IntList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toLongList() {
        final Supplier supplier = Suppliers.ofLongList();
        final BiConsumer accumulator = LongList_Accumulator;
        final BinaryOperator combiner = LongList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toFloatList() {
        final Supplier supplier = Suppliers.ofFloatList();
        final BiConsumer accumulator = FloatList_Accumulator;
        final BinaryOperator combiner = FloatList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * 
     *
     * @return 
     */
    public static Collector toDoubleList() {
        final Supplier supplier = Suppliers.ofDoubleList();
        final BiConsumer accumulator = DoubleList_Accumulator;
        final BinaryOperator combiner = DoubleList_Combiner;

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

    /**
     * 
     *
     * @return 
     */
    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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * Only works for sequential Stream.
     *
     * @param  
     * @param n 
     * @return 
     * @throws UnsupportedOperationException operated by multiple threads
     */
    public static  Collector> first(final int n) {
        N.checkArgNotNegative(n, "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.notNullOrEmpty(a) && N.notNullOrEmpty(b)) {
                throw new UnsupportedOperationException("The 'first' and 'last' Collector only can be used in sequential stream");
            }

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

        return new CollectorImpl<>(supplier, accumulator, combiner, CH_ID);
    }

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

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

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

                dqueue.offerLast(t);
            }
        };

        final BinaryOperator> combiner = (a, b) -> {
            if (N.notNullOrEmpty(a) && N.notNullOrEmpty(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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

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

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

    /**
     * 
     *
     * @param delimiter 
     * @param prefix 
     * @param suffix 
     * @return 
     */
    public static Collector joining(final CharSequence delimiter, final CharSequence prefix, final CharSequence suffix) {
        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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_NOID);
    }

    /**
     * It's copied from StreamEx: https://github.com/amaembo/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 true to the * {@code List} * @see #filtering(Predicate, Collector) * @since 0.6.0 */ public static Collector> filtering(Predicate predicate) { final Collector> downstream = Collectors.toList(); return filtering(predicate, downstream); } /** * It's copied from StreamEx: https://github.com/amaembo/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 #pairing(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 true to the * downstream collector * @see #pairing(Collector, Collector, BiFunction) * @since 0.4.0 */ 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 new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param mapper * @return */ public static Collector> mapping(Function mapper) { return Collectors.mapping(mapper, Collectors. toList()); } /** * * * @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 new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param mapper * @return */ public static Collector> flatMaping(final Function> mapper) { return flatMaping(mapper, Collectors. toList()); } /** * * * @param * @param * @param * @param * @param mapper * @param downstream * @return */ public static Collector flatMaping(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 new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param mapper * @return */ public static Collector> flattMaping(final Function> mapper) { return flattMaping(mapper, Collectors. toList()); } /** * * * @param * @param * @param * @param * @param mapper * @param downstream * @return */ public static Collector flattMaping(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 new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param mapper * @return */ public static Collector> flatmapping(final Function> mapper) { return flatmapping(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) -> { final Collection c = mapper.apply(t); if (N.notNullOrEmpty(c)) { for (U u : c) { downstreamAccumulator.accept(a, u); } } }; return new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param * @param flatMapper * @param mapper * @return */ public static Collector> flatMaping(final Function> flatMapper, final BiFunction mapper) { return flatMaping(flatMapper, mapper, Collectors. toList()); } /** * * * @param * @param * @param * @param * @param * @param flatMapper * @param mapper * @param downstream * @return */ public static Collector flatMaping(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 new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param * @param flatMapper * @param mapper * @return */ public static Collector> flattMaping(final Function> flatMapper, final BiFunction mapper) { return flattMaping(flatMapper, mapper, Collectors. toList()); } /** * * * @param * @param * @param * @param * @param * @param flatMapper * @param mapper * @param downstream * @return */ public static Collector flattMaping(final Function> flatMapper, 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 new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param * @param flatMapper * @param mapper * @return */ public static Collector> flatmapping(final Function> flatMapper, final BiFunction mapper) { return flatmapping(flatMapper, mapper, Collectors. toList()); } /** * * * @param * @param * @param * @param * @param * @param flatMapper * @param mapper * @param downstream * @return */ public static Collector flatmapping(final Function> flatMapper, final BiFunction mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = (a, t) -> { final Collection c = flatMapper.apply(t); if (N.notNullOrEmpty(c)) { for (T2 t2 : c) { downstreamAccumulator.accept(a, mapper.apply(t, t2)); } } }; return new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } /** * * * @param * @param * @param * @param * @param downstream * @param finisher * @return */ public static Collector collectingAndThen(final Collector downstream, final Function finisher) { 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 = Collectors.CH_NOID; } else { characteristics = EnumSet.copyOf(characteristics); characteristics.remove(Characteristics.IDENTITY_FINISH); characteristics = Collections.unmodifiableSet(characteristics); } } return new CollectorImpl<>(downstream.supplier(), downstream.accumulator(), downstream.combiner(), thenFinisher, characteristics); } /** * It's copied from StreamEx: https://github.com/amaembo/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 into 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 keyExtractor a function which classifies input elements. * @return a collector which collects distinct elements to the {@code List}. * @since 0.3.8 */ public static Collector> distinctBy(final Function keyExtractor) { return distinctBy(keyExtractor, Suppliers.ofList()); } /** * * * @param * @param * @param keyExtractor * @param suppplier * @return */ public static > Collector distinctBy(final Function keyExtractor, final Supplier suppplier) { final Supplier> supplier = Suppliers. ofLinkedHashMap(); final BiConsumer, T> accumulator = (map, t) -> { final Object key = keyExtractor.apply(t); if (!map.containsKey(key)) { map.put(key, t); } }; final BinaryOperator> combiner = (a, b) -> { for (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 = suppplier.get(); c.addAll(map.values()); return c; }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * It's copied from StreamEx: https://github.com/amaembo/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 keyExtractor 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 distinctCount(final Function keyExtractor) { final Supplier> supplier = Suppliers. ofSet(); final BiConsumer, T> accumulator = (c, t) -> c.add(keyExtractor.apply(t)); final BinaryOperator> combiner = BinaryOperators.> ofAddAllToBigger(); final Function, Integer> finisher = Set::size; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @return */ public static Collector counting() { final Function accumulator = Counting_Accumulator; final BinaryOperator combiner = Counting_Combiner; return reducing(0L, accumulator, combiner); } /** * * * @param * @return */ public static Collector countingInt() { final Function accumulator = CountingInt_Accumulator; final BinaryOperator combiner = CountingInt_Combiner; return reducing(0, accumulator, combiner); } /** * * * @param * @return */ public static > Collector> min() { return min(Fn.nullsLast()); } /** * * * @param * @param comparator * @return */ public static Collector> min(final Comparator comparator) { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) <= 0 ? a : b; return reducing(op); } /** * * * @param * @param other * @return */ public static > Collector minOrGet(final Supplier other) { return minOrGet(Fn.nullsLast(), other); } /** * * * @param * @param comparator * @param other * @return */ public static Collector minOrGet(final Comparator comparator, final Supplier other) { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) <= 0 ? a : b; return reducingOrGet(op, other); } /** * * * @param * @return */ public static > Collector minOrThrow() { return minOrThrow(Fn.nullsLast()); } /** * * * @param * @param comparator * @return */ public static Collector minOrThrow(final Comparator comparator) { return minOrThrow(comparator, noSuchElementExceptionSupplier); } /** * * * @param * @param comparator * @param exceptionSupplier * @return */ public static Collector minOrThrow(final Comparator comparator, final Supplier exceptionSupplier) { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) <= 0 ? a : b; return reducingOrThrow(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.comparingBy(keyMapper)); } /** * * * @param * @param keyMapper * @param other * @return */ @SuppressWarnings("rawtypes") public static Collector minByOrGet(final Function keyMapper, final Supplier other) { return minOrGet(Comparators.comparingBy(keyMapper), other); } /** * * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector minByOrThrow(final Function keyMapper) { return minOrThrow(Comparators.comparingBy(keyMapper)); } /** * * * @param * @param keyMapper * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector minByOrThrow(final Function keyMapper, final Supplier exceptionSupplier) { return minOrThrow(Comparators.comparingBy(keyMapper), exceptionSupplier); } /** * * * @param * @return */ public static > Collector> max() { return max(Fn.nullsFirst()); } /** * * * @param * @param comparator * @return */ public static Collector> max(final Comparator comparator) { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) >= 0 ? a : b; return reducing(op); } /** * * * @param * @param other * @return */ public static > Collector maxOrGet(final Supplier other) { return maxOrGet(Fn.nullsFirst(), other); } /** * * * @param * @param comparator * @param other * @return */ public static Collector maxOrGet(final Comparator comparator, final Supplier other) { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) >= 0 ? a : b; return reducingOrGet(op, other); } /** * * * @param * @return */ public static > Collector maxOrThrow() { return maxOrThrow(Fn.nullsFirst()); } /** * * * @param * @param comparator * @return */ public static Collector maxOrThrow(final Comparator comparator) { return maxOrThrow(comparator, noSuchElementExceptionSupplier); } /** * * * @param * @param comparator * @param exceptionSupplier * @return */ public static Collector maxOrThrow(final Comparator comparator, final Supplier exceptionSupplier) { N.checkArgNotNull(comparator); final BinaryOperator op = (a, b) -> comparator.compare(a, b) >= 0 ? a : b; return reducingOrThrow(op, exceptionSupplier); } /** * * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector> maxBy(final Function keyMapper) { return max(Comparators.comparingBy(keyMapper)); } /** * * * @param * @param keyMapper * @param other * @return */ @SuppressWarnings("rawtypes") public static Collector maxByOrGet(final Function keyMapper, final Supplier other) { return maxOrGet(Comparators.comparingBy(keyMapper), other); } /** * * * @param * @param keyMapper * @return */ @SuppressWarnings("rawtypes") public static Collector maxByOrThrow(final Function keyMapper) { return maxOrThrow(Comparators.comparingBy(keyMapper)); } /** * * * @param * @param keyMapper * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector maxByOrThrow(final Function keyMapper, final Supplier exceptionSupplier) { return maxOrThrow(Comparators.comparingBy(keyMapper), exceptionSupplier); } /** * It's copied from StreamEx: https://github.com/amaembo/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(Fn.nullsLast()); } /** * It's copied from StreamEx: https://github.com/amaembo/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(Comparator comparator) { return minAll(comparator, Integer.MAX_VALUE); } /** * * * @param * @param comparator * @param atMostSize * @return */ public static Collector> minAll(Comparator comparator, int atMostSize) { return maxAll(Fn.reversedOrder(comparator), atMostSize); } /** * It's copied from StreamEx: https://github.com/amaembo/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(Collector downstream) { return minAll(Fn.nullsLast(), downstream); } /** * It's copied from StreamEx: https://github.com/amaembo/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(Comparator comparator, Collector downstream) { return maxAll(Fn.reversedOrder(comparator), downstream); } /** * * * @param * @param * @param * @param downstream * @return */ @SuppressWarnings("rawtypes") public static Collector>> minAlll(Collector downstream) { return minAlll(Fn.nullsLast(), downstream); } /** * * * @param * @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 * @param comparator * @param downstream * @param finisher * @return */ public static Collector minAlll(final Comparator comparator, final Collector downstream, final Function>, R> finisher) { return maxAlll(Fn.reversedOrder(comparator), downstream, finisher); } /** * It's copied from StreamEx: https://github.com/amaembo/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(Fn.nullsFirst()); } /** * It's copied from StreamEx: https://github.com/amaembo/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(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 { 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; } 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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * It's copied from StreamEx: https://github.com/amaembo/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 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 maximal elements. * @see #maxAll(Comparator, Collector) * @see #maxAll(Comparator) * @see #maxAll() */ @SuppressWarnings("rawtypes") public static Collector maxAll(Collector downstream) { return maxAll(Fn.nullsFirst(), downstream); } /** * It's copied from StreamEx: https://github.com/amaembo/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 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 maximal elements. * @see #maxAll(Comparator) * @see #maxAll(Collector) * @see #maxAll() */ public static Collector maxAll(final Comparator comparator, final Collector downstream) { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final BinaryOperator downstreamCombiner = downstream.combiner(); final MutableBoolean isCollection = MutableBoolean.of(false); final MutableBoolean isMap = MutableBoolean.of(false); final Supplier> supplier = new Supplier<>() { @SuppressWarnings("rawtypes") @Override public Pair get() { final A container = downstreamSupplier.get(); if (container instanceof Collection && ((Collection) container).size() == 0) { try { ((Collection) container).clear(); isCollection.setTrue(); } catch (Exception e) { // ignore } } else if (container instanceof Map && ((Map) container).size() == 0) { try { ((Map) container).clear(); isMap.setTrue(); } catch (Exception e) { // ignore } } return Pair.of((T) none(), container); } }; final BiConsumer, T> accumulator = new BiConsumer<>() { @SuppressWarnings("rawtypes") @Override public void accept(Pair a, T 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, D> finisher = t -> downstream.finisher().apply(t.right); return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param * @param * @param downstream * @return */ @SuppressWarnings("rawtypes") public static Collector>> maxAlll(Collector downstream) { return maxAlll(Fn.nullsFirst(), downstream); } /** * * * @param * @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 * @param comparator * @param downstream * @param finisher * @return */ public static Collector maxAlll(final Comparator comparator, final Collector downstream, final Function>, R> finisher) { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final BinaryOperator downstreamCombiner = downstream.combiner(); final MutableBoolean isCollection = MutableBoolean.of(false); final MutableBoolean isMap = MutableBoolean.of(false); final Supplier> supplier = new Supplier<>() { @SuppressWarnings("rawtypes") @Override public Pair get() { final A container = downstreamSupplier.get(); if (container instanceof Collection && ((Collection) container).size() == 0) { try { ((Collection) container).clear(); isCollection.setTrue(); } catch (Exception e) { // ignore } } else if (container instanceof Map && ((Map) container).size() == 0) { try { ((Map) container).clear(); isMap.setTrue(); } catch (Exception e) { // ignore } } return Pair.of((T) none(), container); } }; final BiConsumer, T> accumulator = new BiConsumer<>() { @SuppressWarnings("rawtypes") @Override public void accept(Pair a, T 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, R> finalFinisher = a -> { final Optional> result = a.left == NONE ? Optional.empty() : Optional.of(Pair.of(a.left, downstream.finisher().apply(a.right))); return finisher.apply(result); }; return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, CH_UNORDERED_NOID); } /** * * * @param * @return */ @SuppressWarnings("rawtypes") public static Collector>> minMax() { return minMax(Fn.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: https://github.com/amaembo/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 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 minimal and maximal * element * @param finisher a {@link BiFunction} which takes minimal and maximal * element 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 * @return */ public static > Collector> minMaxOrThrow() { return minMaxOrThrow(Fn.naturalOrder()); } /** * * * @param * @param comparator * @return */ public static Collector> minMaxOrThrow(final Comparator comparator) { return MoreCollectors.combine(Collectors.minOrThrow(comparator), Collectors.maxOrThrow(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 new CollectorImpl<>(SummingInt_Supplier, accumulator, SummingInt_Combiner, SummingInt_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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(AveragingInt_Supplier, accumulator, AveragingInt_Combiner, AveragingInt_Finisher_op, CH_UNORDERED_NOID); } /** * * * @param * @param mapper * @return */ public static Collector averagingIntOrThrow(final ToIntFunction mapper) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; }; return new CollectorImpl<>(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 new CollectorImpl<>(AveragingLong_Supplier, accumulator, AveragingLong_Combiner, AveragingLong_Finisher_op, CH_UNORDERED_NOID); } /** * * * @param * @param mapper * @return */ public static Collector averagingLongOrThrow(final ToLongFunction mapper) { final BiConsumer accumulator = (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; }; return new CollectorImpl<>(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 new CollectorImpl<>(AveragingDouble_Supplier, accumulator, AveragingDouble_Combiner, AveragingDouble_Finisher_op, CH_UNORDERED_NOID); } /** * * * @param * @param mapper * @return */ public static Collector averagingDoubleOrThrow(final ToDoubleFunction mapper) { final BiConsumer accumulator = (a, t) -> a.add(mapper.applyAsDouble(t)); return new CollectorImpl<>(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 new CollectorImpl<>(AveragingBigInteger_Supplier, accumulator, AveragingBigInteger_Combiner, AveragingBigInteger_Finisher_op, CH_UNORDERED_NOID); } /** * * * @param * @param mapper * @return */ public static Collector averagingBigIntegerOrThrow(final Function mapper) { final BiConsumer, T> accumulator = (a, t) -> { a.setLeft(a.left.add(mapper.apply(t))); a.right[0] += 1; }; return new CollectorImpl<>(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 new CollectorImpl<>(AveragingBigDecimal_Supplier, accumulator, AveragingBigDecimal_Combiner, AveragingBigDecimal_Finisher_op, CH_UNORDERED_NOID); } /** * * * @param * @param mapper * @return */ public static Collector averagingBigDecimalOrThrow(final Function mapper) { final BiConsumer, T> accumulator = (a, t) -> { a.setLeft(a.left.add(mapper.apply(t))); a.right[0] += 1; }; return new CollectorImpl<>(AveragingBigDecimal_Supplier, accumulator, AveragingBigDecimal_Combiner, AveragingBigDecimal_Finisher, CH_UNORDERED_NOID); } /** * * * @param * @param mapper * @return */ public static Collector summarizingChar(final ToCharFunction mapper) { final Supplier supplier = SummarizingChar_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsChar(t)); final BinaryOperator combiner = SummarizingChar_Combiner; return new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ public static Collector summarizingByte(final ToByteFunction mapper) { final Supplier supplier = SummarizingByte_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsByte(t)); final BinaryOperator combiner = SummarizingByte_Combiner; return new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ public static Collector summarizingShort(final ToShortFunction mapper) { final Supplier supplier = SummarizingShort_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsShort(t)); final BinaryOperator combiner = SummarizingShort_Combiner; return new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ 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 new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ 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 new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ public static Collector summarizingFloat(final ToFloatFunction mapper) { final Supplier supplier = SummarizingFloat_Supplier; final BiConsumer accumulator = (a, t) -> a.accept(mapper.applyAsFloat(t)); final BinaryOperator combiner = SummarizingFloat_Combiner; return new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ 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 new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ 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 new CollectorImpl<>(supplier, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param mapper * @return */ 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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param op * @param other * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrGet(final BinaryOperator op, final Supplier other) { 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 : other.get(); return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param op * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrThrow(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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param op * @return */ public static Collector reducingOrThrow(final BinaryOperator op) { return reducingOrThrow(op, noSuchElementExceptionSupplier); } /** * * * @param * @param * @param identity * @param mapper * @param op * @return */ public static Collector reducing(final U 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, U> finisher = (Function) Reducing_Finisher_0; return new CollectorImpl<>(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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } @SuppressWarnings("unchecked") 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(T t) { if (present) { value = op.apply(value, t); } else { value = t; present = true; } } } private static class MappingOptHolder implements Consumer { Function mapper; 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(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 other * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrGet(final Function mapper, final BinaryOperator op, final Supplier other) { final Supplier> supplier = () -> new MappingOptHolder<>(mapper, op); final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator_2; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner_2; final Function, U> finisher = a -> a.present ? a.value : other.get(); return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param * @param mapper * @param op * @param exceptionSupplier * @return */ @SuppressWarnings("rawtypes") public static Collector reducingOrThrow(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, U> finisher = a -> { if (a.present) { return a.value; } else { throw exceptionSupplier.get(); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param * @param mapper * @param op * @return */ public static Collector reducingOrThrow(final Function mapper, final BinaryOperator op) { return reducingOrThrow(mapper, op, noSuchElementExceptionSupplier); } /** * It's copied from StreamEx: https://github.com/amaembo/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. * @since 0.5.0 */ 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 = t.length(); } 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--; } a.right = i; break; } } } }; final BinaryOperator> combiner = (a, b) -> { if (a.right == -1) { return b; } if (b.right != -1) { accumulator.accept(a, b.left.subSequence(0, b.right)); } return a; }; final Function, String> finisher = a -> a.left == null ? "" : a.left.subSequence(0, a.right).toString(); return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * It's copied from StreamEx: https://github.com/amaembo/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. * @since 0.5.0 */ 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--; } a.right = i; break; } } } }; final BinaryOperator> combiner = (a, b) -> { if (a.right == -1) { return b; } if (b.right != -1) { accumulator.accept(a, b.left.subSequence(b.left.length() - b.right, b.left.length())); } return a; }; final Function, String> finisher = a -> a.left == null ? "" : a.left.subSequence(a.left.length() - a.right, a.left.length()).toString(); return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param * @param keyMapper * @return */ public static Collector>> groupingBy(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 */ public static > Collector groupingBy(final Function keyMapper, final Collector downstream, final Supplier mapFactory) { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final Function mappingFunction = k -> downstreamSupplier.get(); final BiConsumer, T> accumulator = (m, t) -> { K key = N.checkArgNotNull(keyMapper.apply(t), "element cannot be mapped to a null key"); 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 new CollectorImpl<>(mangledFactory, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param * @param keyMapper * @return */ public static Collector>> groupingByConcurrent(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(Function keyMapper, Collector downstream) { final Supplier> mapFactory = Suppliers.ofConcurrentMap(); return groupingByConcurrent(keyMapper, downstream, mapFactory); } /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return */ public static > Collector groupingByConcurrent(final Function keyMapper, Collector downstream, final Supplier mapFactory) { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final Function mappingFunction = k -> downstreamSupplier.get(); final BiConsumer, T> accumulator = (m, t) -> { K key = N.checkArgNotNull(keyMapper.apply(t), "element cannot be mapped to a null key"); A container = computeIfAbsent(m, key, mappingFunction); downstreamAccumulator.accept(container, t); }; final BinaryOperator> combiner = Collectors.> mapMerger(downstream.combiner()); @SuppressWarnings("unchecked") final Supplier> mangledFactory = (Supplier>) mapFactory; if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(mangledFactory, accumulator, 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 new CollectorImpl<>(mangledFactory, accumulator, combiner, finisher, CH_UNORDERED_NOID); } } /** * * * @param * @param predicate * @return */ public static Collector>> partitioningBy(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 new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * * * @param * @param * @param keyMapper * @return */ public static Collector> countingBy(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> countingIntBy(Function keyMapper) { return countingIntBy(keyMapper, Suppliers. ofMap()); } /** * * * @param * @param * @param * @param keyMapper * @param mapFactory * @return */ public static > Collector countingIntBy(final Function keyMapper, final Supplier mapFactory) { final Collector downstream = countingInt(); 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(Function keyMapper, 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(Function keyMapper, Function valueMapper, 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 = (BinaryOperator) mapMerger(mergeFunction); return new CollectorImpl<>(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(Function keyMapper, 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(Function keyMapper, Function valueMapper, 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 #toMap(Function, Function) */ public static Collector> toLinkedHashMap(Function keyMapper, 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(Function keyMapper, Function valueMapper, 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(Function keyMapper, 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, 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(Function keyMapper, Function valueMapper, 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, Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> merge(map, keyMapper.apply(element), valueMapper.apply(element), mergeFunction); final BinaryOperator combiner = (BinaryOperator) concurrentMapMerger(mergeFunction); return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param * @param * @param keyMapper * @param valueMapper * @return */ public static Collector> toBiMap(Function keyMapper, 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(Function keyMapper, Function valueMapper, 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(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(Function keyMapper, 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 new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param * @param * @param keyMapper * @param flatValueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatMapingValueToMultimap(final Function keyMapper, final Function> flatValueMapper) { return flatMapingValueToMultimap(keyMapper, flatValueMapper, Suppliers. ofListMultimap()); } /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param flatValueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatMapingValueToMultimap( final Function keyMapper, final Function> flatValueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final K key = keyMapper.apply(element); try (java.util.stream.Stream stream = flatValueMapper.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 new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param * @param * @param keyMapper * @param flatValueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flattMapingValueToMultimap(final Function keyMapper, final Function> flatValueMapper) { return flattMapingValueToMultimap(keyMapper, flatValueMapper, Suppliers. ofListMultimap()); } /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param flatValueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flattMapingValueToMultimap( final Function keyMapper, final Function> flatValueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final K key = keyMapper.apply(element); try (Stream stream = flatValueMapper.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 new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param * @param * @param keyMapper * @param flatValueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatmappingValueToMultimap(final Function keyMapper, final Function> flatValueMapper) { return flatmappingValueToMultimap(keyMapper, flatValueMapper, Suppliers. ofListMultimap()); } /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param flatValueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatmappingValueToMultimap( final Function keyMapper, final Function> flatValueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final K key = keyMapper.apply(element); final Collection values = flatValueMapper.apply(element); if (N.notNullOrEmpty(values)) { for (V value : values) { map.put(key, value); } } }; final BinaryOperator combiner = Collectors. multimapMerger(); return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatMapingKeyToMultimap( final Function> flatKeyMapper, final Function valueMapper) { return flatMapingKeyToMultimap(flatKeyMapper, valueMapper, Suppliers. ofListMultimap()); } /** * * * @param * @param * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatMapingKeyToMultimap( final Function> flatKeyMapper, final Function valueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final V value = valueMapper.apply(element); try (java.util.stream.Stream stream = flatKeyMapper.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 new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flattMapingKeyToMultimap(final Function> flatKeyMapper, final Function valueMapper) { return flattMapingKeyToMultimap(flatKeyMapper, valueMapper, Suppliers. ofListMultimap()); } /** * * * @param * @param * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flattMapingKeyToMultimap( final Function> flatKeyMapper, final Function valueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final V value = valueMapper.apply(element); try (Stream stream = flatKeyMapper.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 new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } /** * * * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ public static Collector> flatmappingKeyToMultimap( final Function> flatKeyMapper, final Function valueMapper) { return flatmappingKeyToMultimap(flatKeyMapper, valueMapper, Suppliers. ofListMultimap()); } /** * * * @param * @param * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ public static , M extends Multimap> Collector flatmappingKeyToMultimap( final Function> flatKeyMapper, final Function valueMapper, final Supplier mapFactory) { final BiConsumer accumulator = (map, element) -> { final V value = valueMapper.apply(element); final Collection keys = flatKeyMapper.apply(element); if (N.notNullOrEmpty(keys)) { for (K key : keys) { map.put(key, value); } } }; final BinaryOperator combiner = Collectors. multimapMerger(); return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } // public static Collector toDataSet(final String beanName, final Class beanClass, final List columnNames) { // @SuppressWarnings("rawtypes") // final Collector, List> collector = (Collector) toList(); // // final Function, DataSet> finisher = new Function, DataSet>() { // @Override // public DataSet apply(List t) { // return N.newDataSet(beanName, beanClass, columnNames, t); // } // }; // // return new CollectorImpl, DataSet>(collector.supplier(), collector.accumulator(), collector.combiner(), finisher); // } static void replaceAll(Map map, BiFunction function) { N.checkArgNotNull(function); try { for (Map.Entry entry : map.entrySet()) { entry.setValue(function.apply(entry.getKey(), entry.getValue())); } } catch (IllegalStateException ise) { throw new ConcurrentModificationException(ise); } } private static V computeIfAbsent(Map map, K key, Function mappingFunction) { N.checkArgNotNull(mappingFunction); V v = null; if ((v = map.get(key)) == null) { 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 (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 (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 (Map.Entry e : m2.entrySet()) { N.checkArgNotNull(e.getValue()); key = e.getKey(); value = e.getValue(); if (N.notNullOrEmpty(value)) { V oldValue = m1.get(key); if (oldValue == null) { m1.putAll(key, value); } else { oldValue.addAll(value); } } } return m1; }; } static void merge(Map map, K key, V value, 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)); } } public abstract static class MoreCollectors extends Collectors { protected 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 new CollectorImpl<>(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 new CollectorImpl<>(SummingInt_Supplier_3, accumulator, SummingInt_Combiner_3, SummingInt_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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(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 new CollectorImpl<>(AveragingBigDecimal_Supplier_3, accumulator, AveragingBigDecimal_Combiner_3, AveragingBigDecimal_Finisher_3, CH_UNORDERED_NOID); } /** * * * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @return */ public static Collector, Tuple2> combine(final Collector collector1, final Collector collector2) { final Supplier supplier1 = collector1.supplier(); final Supplier supplier2 = collector2.supplier(); final BiConsumer accumulator1 = collector1.accumulator(); final BiConsumer accumulator2 = collector2.accumulator(); final BinaryOperator combiner1 = collector1.combiner(); final BinaryOperator combiner2 = collector2.combiner(); final Function finisher1 = collector1.finisher(); final Function finisher2 = collector2.finisher(); final Supplier> supplier = () -> Tuple.of(supplier1.get(), supplier2.get()); final BiConsumer, T> accumulator = (acct, e) -> { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); }; final BinaryOperator> combiner = (t, u) -> Tuple.of(combiner1.apply(t._1, u._1), combiner2.apply(t._2, u._2)); List common = N.intersection(collector1.characteristics(), collector2.characteristics()); final Set characteristics = N.isNullOrEmpty(common) ? CH_NOID : N.newHashSet(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, Tuple2> finisher = t -> Tuple.of(finisher1.apply(t._1), finisher2.apply(t._2)); return new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } /** * * * @param * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @param finisher * @return */ public static Collector, R> combine(final Collector collector1, final Collector collector2, final BiFunction finisher) { final Supplier supplier1 = collector1.supplier(); final Supplier supplier2 = collector2.supplier(); final BiConsumer accumulator1 = collector1.accumulator(); final BiConsumer accumulator2 = collector2.accumulator(); final BinaryOperator combiner1 = collector1.combiner(); final BinaryOperator combiner2 = collector2.combiner(); final Function finisher1 = collector1.finisher(); final Function finisher2 = collector2.finisher(); final Supplier> supplier = () -> Tuple.of(supplier1.get(), supplier2.get()); final BiConsumer, T> accumulator = (acct, e) -> { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); }; final BinaryOperator> combiner = (t, u) -> Tuple.of(combiner1.apply(t._1, u._1), combiner2.apply(t._2, u._2)); final List common = N.intersection(collector1.characteristics(), collector2.characteristics()); common.remove(Characteristics.IDENTITY_FINISH); final Set characteristics = N.isNullOrEmpty(common) ? CH_NOID : N.newHashSet(common); final Function, R> finalFinisher = t -> finisher.apply(finisher1.apply(t._1), finisher2.apply(t._2)); return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, characteristics); } /** * * * @param * @param * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @param collector3 * @return */ public static Collector, Tuple3> combine(final Collector collector1, final Collector collector2, final Collector collector3) { final Supplier supplier1 = collector1.supplier(); final Supplier supplier2 = collector2.supplier(); final Supplier supplier3 = collector3.supplier(); final BiConsumer accumulator1 = collector1.accumulator(); final BiConsumer accumulator2 = collector2.accumulator(); final BiConsumer accumulator3 = collector3.accumulator(); final BinaryOperator combiner1 = collector1.combiner(); final BinaryOperator combiner2 = collector2.combiner(); final BinaryOperator combiner3 = collector3.combiner(); final Function finisher1 = collector1.finisher(); final Function finisher2 = collector2.finisher(); final Function finisher3 = collector3.finisher(); final Supplier> supplier = () -> Tuple.of(supplier1.get(), supplier2.get(), supplier3.get()); final BiConsumer, T> accumulator = (acct, e) -> { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); accumulator3.accept(acct._3, e); }; final BinaryOperator> combiner = (t, u) -> Tuple.of(combiner1.apply(t._1, u._1), combiner2.apply(t._2, u._2), combiner3.apply(t._3, u._3)); List common = N.intersection(collector1.characteristics(), collector2.characteristics()); if (N.notNullOrEmpty(common)) { common = N.intersection(common, collector3.characteristics()); } final Set characteristics = N.isNullOrEmpty(common) ? CH_NOID : N.newHashSet(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, Tuple3> finisher = t -> Tuple.of(finisher1.apply(t._1), finisher2.apply(t._2), finisher3.apply(t._3)); return new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } /** * * * @param * @param * @param * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @param collector3 * @param finisher * @return */ public static Collector, R> combine(final Collector collector1, final Collector collector2, final Collector collector3, final TriFunction finisher) { final Supplier supplier1 = collector1.supplier(); final Supplier supplier2 = collector2.supplier(); final Supplier supplier3 = collector3.supplier(); final BiConsumer accumulator1 = collector1.accumulator(); final BiConsumer accumulator2 = collector2.accumulator(); final BiConsumer accumulator3 = collector3.accumulator(); final BinaryOperator combiner1 = collector1.combiner(); final BinaryOperator combiner2 = collector2.combiner(); final BinaryOperator combiner3 = collector3.combiner(); final Function finisher1 = collector1.finisher(); final Function finisher2 = collector2.finisher(); final Function finisher3 = collector3.finisher(); final Supplier> supplier = () -> Tuple.of(supplier1.get(), supplier2.get(), supplier3.get()); final BiConsumer, T> accumulator = (acct, e) -> { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); accumulator3.accept(acct._3, e); }; final BinaryOperator> combiner = (t, u) -> Tuple.of(combiner1.apply(t._1, u._1), combiner2.apply(t._2, u._2), combiner3.apply(t._3, u._3)); List common = N.intersection(collector1.characteristics(), collector2.characteristics()); if (N.notNullOrEmpty(common)) { common = N.intersection(common, collector3.characteristics()); } common.remove(Characteristics.IDENTITY_FINISH); final Set characteristics = N.isNullOrEmpty(common) ? CH_NOID : N.newHashSet(common); final Function, R> finalFinisher = t -> finisher.apply(finisher1.apply(t._1), finisher2.apply(t._2), finisher3.apply(t._3)); return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, characteristics); } /** * * * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @param collector3 * @param collector4 * @return */ @SuppressWarnings("rawtypes") public static Collector, Tuple4> combine( final Collector collector1, final Collector collector2, final Collector collector3, final Collector collector4) { final List> collectors = (List) Array.asList(collector1, collector2, collector3, collector4); final Function, Tuple4> func = Tuple::from; return (Collector) collectingAndThen(combine(collectors), func); } /** * * * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @param collector3 * @param collector4 * @param collector5 * @return */ @SuppressWarnings("rawtypes") public static Collector, Tuple5> combine( final Collector collector1, final Collector collector2, final Collector collector3, final Collector collector4, final Collector collector5) { final List> collectors = (List) Array.asList(collector1, collector2, collector3, collector4, collector5); final Function, Tuple5> func = Tuple::from; return (Collector) collectingAndThen(combine(collectors), func); } /** * * * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @param collector3 * @param collector4 * @param collector5 * @param collector6 * @return */ @SuppressWarnings("rawtypes") public static Collector, Tuple6> combine( final Collector collector1, final Collector collector2, final Collector collector3, final Collector collector4, final Collector collector5, final Collector collector6) { final List> collectors = (List) Array.asList(collector1, collector2, collector3, collector4, collector5, collector6); final Function, Tuple6> func = Tuple::from; return (Collector) collectingAndThen(combine(collectors), func); } /** * * * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param * @param collector1 * @param collector2 * @param collector3 * @param collector4 * @param collector5 * @param collector6 * @param collector7 * @return */ @SuppressWarnings("rawtypes") public static Collector, Tuple7> combine( final Collector collector1, final Collector collector2, final Collector collector3, final Collector collector4, final Collector collector5, final Collector collector6, final Collector collector7) { final List> collectors = (List) Array.asList(collector1, collector2, collector3, collector4, collector5, collector6, collector7); final Function, Tuple7> func = Tuple::from; return (Collector) collectingAndThen(combine(collectors), func); } /** * * * @param * @param collectors * @return * @see Tuple#from(Collection) */ @SuppressWarnings("rawtypes") public static Collector> combine(final Collection> collectors) { //NOSONAR N.checkArgument(N.notNullOrEmpty(collectors), "The specified 'collectors' can't be null or empty"); final int len = collectors.size(); final java.util.stream.Collector[] cs = collectors.toArray(new java.util.stream.Collector[len]); final Supplier supplier = () -> { final Object[] a = new Object[len]; for (int i = 0; i < len; i++) { a[i] = cs[i].supplier().get(); } return a; }; final BiConsumer accumulator = (a, e) -> { for (int i = 0; i < len; i++) { cs[i].accumulator().accept(a[i], e); } }; final BinaryOperator combiner = (a, b) -> { for (int i = 0; i < len; i++) { a[i] = cs[i].combiner().apply(a[i], b[i]); } return a; }; Collection common = cs[0].characteristics(); for (int i = 1; i < len && N.notNullOrEmpty(common); i++) { common = N.intersection(common, cs[i].characteristics()); } final Set characteristics = N.isNullOrEmpty(common) ? CH_NOID : N.newHashSet(common); Function> finisher = null; if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { finisher = N::asList; } else { finisher = a -> { for (int i = 0; i < len; i++) { a[i] = cs[i].finisher().apply(a[i]); } return N.asList(a); }; } return (Collector) new CollectorImpl<>(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 new Collectors.CollectorImpl<>(collector.supplier(), collector.accumulator(), collector.combiner(), finisher, Collectors.CH_NOID); } } }