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

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

/*
 * 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.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collector.Characteristics;

import com.landawn.abacus.DataSet;
import com.landawn.abacus.exception.DuplicatedResultException;
import com.landawn.abacus.util.Array;
import com.landawn.abacus.util.BiMap;
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.ContinuableFuture;
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.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.MutableLong;
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.u.Holder;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.BooleanSupplier;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.IntFunction;
import com.landawn.abacus.util.function.Predicate;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.function.ToByteFunction;
import com.landawn.abacus.util.function.ToCharFunction;
import com.landawn.abacus.util.function.ToDoubleFunction;
import com.landawn.abacus.util.function.ToFloatFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.ToLongFunction;
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();

    @Deprecated
    static final Set CH_CONCURRENT_ID = Collections
            .unmodifiableSet(EnumSet.of(Characteristics.CONCURRENT, Characteristics.UNORDERED, Characteristics.IDENTITY_FINISH));
    @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();

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

    static final Function, ImmutableList> ImmutableList_Finisher = new Function, ImmutableList>() {
        @Override
        public ImmutableList apply(List t) {
            return ImmutableList.of(t);
        }
    };

    static final Function, ImmutableSet> ImmutableSet_Finisher = new Function, ImmutableSet>() {
        @Override
        public ImmutableSet apply(Set t) {
            return ImmutableSet.of(t);
        }
    };

    static final Function, ImmutableMap> ImmutableMap_Finisher = new Function, ImmutableMap>() {
        @Override
        public ImmutableMap apply(Map t) {
            return ImmutableMap.of(t);
        }
    };

    static final BiConsumer, Object> Multiset_Accumulator = new BiConsumer, Object>() {
        @Override
        public void accept(Multiset c, Object t) {
            c.add(t);
        }
    };

    static final BinaryOperator> Multiset_Combiner = new BinaryOperator>() {
        @Override
        public Multiset apply(Multiset a, Multiset b) {
            a.addAll(b);
            return a;
        }
    };

    static final BiConsumer, Object> LongMultiset_Accumulator = new BiConsumer, Object>() {
        @Override
        public void accept(LongMultiset c, Object t) {
            c.add(t);
        }
    };

    static final BinaryOperator> LongMultiset_Combiner = new BinaryOperator>() {
        @Override
        public LongMultiset apply(LongMultiset a, LongMultiset b) {
            a.addAll(b);
            return a;
        }
    };

    static final BiConsumer BooleanList_Accumulator = new BiConsumer() {
        @Override
        public void accept(BooleanList c, Boolean t) {
            c.add(t.booleanValue());
        }
    };

    static final BinaryOperator BooleanList_Combiner = new BinaryOperator() {
        @Override
        public BooleanList apply(BooleanList a, BooleanList b) {
            a.addAll(b);
            return a;
        }
    };

    static final Function BooleanArray_Finisher = new Function() {
        @Override
        public boolean[] apply(BooleanList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer CharList_Accumulator = new BiConsumer() {
        @Override
        public void accept(CharList c, Character t) {
            c.add(t.charValue());
        }
    };

    static final BinaryOperator CharList_Combiner = new BinaryOperator() {
        @Override
        public CharList apply(CharList a, CharList b) {
            a.addAll(b);
            return a;
        }
    };

    static final Function CharArray_Finisher = new Function() {
        @Override
        public char[] apply(CharList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer ByteList_Accumulator = new BiConsumer() {
        @Override
        public void accept(ByteList c, Byte t) {
            c.add(t.byteValue());
        }
    };

    static final BinaryOperator ByteList_Combiner = new BinaryOperator() {
        @Override
        public ByteList apply(ByteList a, ByteList b) {
            if (a.size() >= b.size()) {
                a.addAll(b);
                return a;
            } else {
                b.addAll(a);
                return b;
            }
        }
    };

    static final Function ByteArray_Finisher = new Function() {
        @Override
        public byte[] apply(ByteList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer ShortList_Accumulator = new BiConsumer() {
        @Override
        public void accept(ShortList c, Short t) {
            c.add(t.shortValue());
        }
    };

    static final BinaryOperator ShortList_Combiner = new BinaryOperator() {
        @Override
        public ShortList apply(ShortList a, ShortList b) {
            if (a.size() >= b.size()) {
                a.addAll(b);
                return a;
            } else {
                b.addAll(a);
                return b;
            }
        }
    };

    static final Function ShortArray_Finisher = new Function() {
        @Override
        public short[] apply(ShortList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer IntList_Accumulator = new BiConsumer() {
        @Override
        public void accept(IntList c, Integer t) {
            c.add(t.intValue());
        }
    };

    static final BinaryOperator IntList_Combiner = new BinaryOperator() {
        @Override
        public IntList apply(IntList a, IntList b) {
            if (a.size() >= b.size()) {
                a.addAll(b);
                return a;
            } else {
                b.addAll(a);
                return b;
            }
        }
    };

    static final Function IntArray_Finisher = new Function() {
        @Override
        public int[] apply(IntList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer LongList_Accumulator = new BiConsumer() {
        @Override
        public void accept(LongList c, Long t) {
            c.add(t.longValue());
        }
    };

    static final BinaryOperator LongList_Combiner = new BinaryOperator() {
        @Override
        public LongList apply(LongList a, LongList b) {
            if (a.size() >= b.size()) {
                a.addAll(b);
                return a;
            } else {
                b.addAll(a);
                return b;
            }
        }
    };

    static final Function LongArray_Finisher = new Function() {
        @Override
        public long[] apply(LongList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer FloatList_Accumulator = new BiConsumer() {
        @Override
        public void accept(FloatList c, Float t) {
            c.add(t.floatValue());
        }
    };

    static final BinaryOperator FloatList_Combiner = new BinaryOperator() {
        @Override
        public FloatList apply(FloatList a, FloatList b) {
            if (a.size() >= b.size()) {
                a.addAll(b);
                return a;
            } else {
                b.addAll(a);
                return b;
            }
        }
    };

    static final Function FloatArray_Finisher = new Function() {
        @Override
        public float[] apply(FloatList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer DoubleList_Accumulator = new BiConsumer() {
        @Override
        public void accept(DoubleList c, Double t) {
            c.add(t.doubleValue());
        }
    };

    static final BinaryOperator DoubleList_Combiner = new BinaryOperator() {
        @Override
        public DoubleList apply(DoubleList a, DoubleList b) {
            if (a.size() >= b.size()) {
                a.addAll(b);
                return a;
            } else {
                b.addAll(a);
                return b;
            }
        }
    };

    static final Function DoubleArray_Finisher = new Function() {
        @Override
        public double[] apply(DoubleList t) {
            return t.trimToSize().array();
        }
    };

    static final BiConsumer Joiner_Accumulator = new BiConsumer() {
        @Override
        public void accept(Joiner a, CharSequence t) {
            a.append(t);
        }
    };

    static final BinaryOperator Joiner_Combiner = new BinaryOperator() {
        @Override
        public Joiner apply(Joiner a, Joiner 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 = new Function() {
        @Override
        public String apply(Joiner a) {
            return a.toString();
        }
    };

    static final Function Counting_Accumulator = new Function() {
        @Override
        public Long apply(Object t) {
            return 1L;
        }
    };

    static final BinaryOperator Counting_Combiner = new BinaryOperator() {
        @Override
        public Long apply(Long a, Long b) {
            return a.longValue() + b.longValue();
        }
    };

    static final Function CountingInt_Accumulator = new Function() {
        @Override
        public Integer apply(Object t) {
            return 1;
        }
    };

    static final BinaryOperator CountingInt_Combiner = new BinaryOperator() {
        @Override
        public Integer apply(Integer a, Integer b) {
            return a.intValue() + b.intValue();
        }
    };

    static final Supplier SummingInt_Supplier = new Supplier() {
        @Override
        public long[] get() {
            return new long[1];
        }
    };

    static final BinaryOperator SummingInt_Combiner = new BinaryOperator() {
        @Override
        public long[] apply(long[] a, long[] b) {
            a[0] += b[0];
            return a;
        }
    };

    static final Function SummingInt_Finisher = new Function() {
        @Override
        public Integer apply(long[] a) {
            return N.toIntExact(a[0]);
        }
    };

    static final Supplier SummingInt_Supplier_2 = new Supplier() {
        @Override
        public long[] get() {
            return new long[2];
        }
    };

    static final BinaryOperator SummingInt_Combiner_2 = new BinaryOperator() {
        @Override
        public long[] apply(long[] a, long[] b) {
            a[0] += b[0];
            a[1] += b[1];
            return a;
        }
    };

    static final Function SummingInt_Finisher_2 = new Function() {
        @Override
        public OptionalInt apply(long[] a) {
            return a[1] == 0 ? OptionalInt.empty() : OptionalInt.of(N.toIntExact(a[0]));
        }
    };

    static final Supplier SummingLong_Supplier = new Supplier() {
        @Override
        public long[] get() {
            return new long[1];
        }
    };

    static final BinaryOperator SummingLong_Combiner = new BinaryOperator() {
        @Override
        public long[] apply(long[] a, long[] b) {
            a[0] += b[0];
            return a;
        }
    };

    static final Function SummingLong_Finisher = new Function() {
        @Override
        public Long apply(long[] a) {
            return a[0];
        }
    };

    static final Supplier SummingLong_Supplier_2 = new Supplier() {
        @Override
        public long[] get() {
            return new long[2];
        }
    };

    static final BinaryOperator SummingLong_Combiner_2 = new BinaryOperator() {
        @Override
        public long[] apply(long[] a, long[] b) {
            a[0] += b[0];
            a[1] += b[1];
            return a;
        }
    };

    static final Function SummingLong_Finisher_2 = new Function() {
        @Override
        public OptionalLong apply(long[] a) {
            return a[1] == 0 ? OptionalLong.empty() : OptionalLong.of(a[0]);
        }
    };

    static final Supplier SummingDouble_Supplier = new Supplier() {
        @Override
        public KahanSummation get() {
            return new KahanSummation();
        }
    };

    static final BinaryOperator SummingDouble_Combiner = new BinaryOperator() {
        @Override
        public KahanSummation apply(KahanSummation a, KahanSummation b) {
            a.combine(b);
            return a;
        }
    };

    static final Function SummingDouble_Finisher = new Function() {
        @Override
        public Double apply(KahanSummation a) {
            return a.sum();
        }
    };

    static final Supplier SummingDouble_Supplier_2 = new Supplier() {
        @Override
        public KahanSummation get() {
            return new KahanSummation();
        }
    };

    static final BinaryOperator SummingDouble_Combiner_2 = new BinaryOperator() {
        @Override
        public KahanSummation apply(KahanSummation a, KahanSummation b) {
            a.combine(b);

            return a;
        }
    };

    static final Function SummingDouble_Finisher_2 = new Function() {
        @Override
        public OptionalDouble apply(KahanSummation a) {
            return a.count() == 0 ? OptionalDouble.empty() : OptionalDouble.of(a.sum());
        }
    };

    static final Supplier SummingBigInteger_Supplier = new Supplier() {
        @Override
        public BigInteger[] get() {
            return new BigInteger[] { BigInteger.ZERO };
        }
    };

    static final BinaryOperator SummingBigInteger_Combiner = new BinaryOperator() {
        @Override
        public BigInteger[] apply(BigInteger[] a, BigInteger[] b) {
            a[0] = a[0].add(b[0]);
            return a;
        }
    };

    static final Function SummingBigInteger_Finisher = new Function() {
        @Override
        public BigInteger apply(BigInteger[] a) {
            return a[0];
        }
    };

    static final Supplier SummingBigDecimal_Supplier = new Supplier() {
        @Override
        public BigDecimal[] get() {
            return new BigDecimal[] { BigDecimal.ZERO };
        }
    };

    static final BinaryOperator SummingBigDecimal_Combiner = new BinaryOperator() {
        @Override
        public BigDecimal[] apply(BigDecimal[] a, BigDecimal[] b) {
            a[0] = a[0].add(b[0]);
            return a;
        }
    };

    static final Function SummingBigDecimal_Finisher = new Function() {
        @Override
        public BigDecimal apply(BigDecimal[] a) {
            return a[0];
        }
    };

    static final Supplier AveragingInt_Supplier = new Supplier() {
        @Override
        public long[] get() {
            return new long[2];
        }
    };

    static final BinaryOperator AveragingInt_Combiner = new BinaryOperator() {
        @Override
        public long[] apply(long[] a, long[] b) {
            a[0] += b[0];
            a[1] += b[1];
            return a;
        }
    };

    static final Function AveragingInt_Finisher = new Function() {
        @Override
        public Double apply(long[] a) {
            return a[1] == 0 ? 0d : ((double) a[0]) / a[1];
        }
    };

    static final Function AveragingInt_Finisher_2 = new Function() {
        @Override
        public OptionalDouble apply(long[] a) {
            if (a[1] == 0) {
                return OptionalDouble.empty();
            } else {
                return OptionalDouble.of(((double) a[0]) / a[1]);
            }
        }
    };

    static final Supplier AveragingLong_Supplier = new Supplier() {
        @Override
        public long[] get() {
            return new long[2];
        }
    };

    static final BinaryOperator AveragingLong_Combiner = new BinaryOperator() {
        @Override
        public long[] apply(long[] a, long[] b) {
            a[0] += b[0];
            a[1] += b[1];
            return a;
        }
    };

    static final Function AveragingLong_Finisher = new Function() {
        @Override
        public Double apply(long[] a) {
            return a[1] == 0 ? 0d : ((double) a[0]) / a[1];
        }
    };

    static final Function AveragingLong_Finisher_2 = new Function() {
        @Override
        public OptionalDouble apply(long[] a) {
            if (a[1] == 0) {
                return OptionalDouble.empty();
            } else {
                return OptionalDouble.of(((double) a[0]) / a[1]);
            }
        }
    };

    static final Supplier AveragingDouble_Supplier = new Supplier() {
        @Override
        public KahanSummation get() {
            return new KahanSummation();
        }
    };

    static final BinaryOperator AveragingDouble_Combiner = new BinaryOperator() {
        @Override
        public KahanSummation apply(KahanSummation a, KahanSummation b) {
            a.combine(b);
            return a;
        }
    };

    static final Function AveragingDouble_Finisher = new Function() {
        @Override
        public Double apply(KahanSummation a) {
            return a.average().orElse(0);
        }
    };

    static final Function AveragingDouble_Finisher_2 = new Function() {
        @Override
        public OptionalDouble apply(KahanSummation a) {
            return a.average();
        }
    };

    static final Supplier> AveragingBigInteger_Supplier = new Supplier>() {
        @Override
        public Pair get() {
            return Pair.of(BigInteger.ZERO, MutableLong.of(0));
        }
    };

    static final BinaryOperator> AveragingBigInteger_Combiner = new BinaryOperator>() {
        @Override
        public Pair apply(Pair a, Pair b) {
            a.setLeft(a.left.add(b.left));
            a.right.add(b.right.value());
            return a;
        }
    };

    static final Function, BigDecimal> AveragingBigInteger_Finisher = new Function, BigDecimal>() {
        @Override
        public BigDecimal apply(Pair a) {
            return a.right.value() == 0 ? BigDecimal.ZERO : new BigDecimal(a.left).divide(new BigDecimal(a.right.value()));
        }
    };

    static final Supplier> AveragingBigDecimal_Supplier = new Supplier>() {
        @Override
        public Pair get() {
            return Pair.of(BigDecimal.ZERO, MutableLong.of(0));
        }
    };

    static final BinaryOperator> AveragingBigDecimal_Combiner = new BinaryOperator>() {
        @Override
        public Pair apply(Pair a, Pair b) {
            a.setLeft(a.left.add(b.left));
            a.right.add(b.right.value());
            return a;
        }
    };

    static final Function, BigDecimal> AveragingBigDecimal_Finisher = new Function, BigDecimal>() {
        @Override
        public BigDecimal apply(Pair a) {
            return a.right.value() == 0 ? BigDecimal.ZERO : a.left.divide(new BigDecimal(a.right.value()));
        }
    };

    static final Supplier SummarizingChar_Supplier = new Supplier() {
        @Override
        public CharSummaryStatistics get() {
            return new CharSummaryStatistics();
        }
    };

    static final BinaryOperator SummarizingChar_Combiner = new BinaryOperator() {
        @Override
        public CharSummaryStatistics apply(CharSummaryStatistics a, CharSummaryStatistics b) {
            a.combine(b);
            return a;
        }
    };

    static final Supplier SummarizingByte_Supplier = new Supplier() {
        @Override
        public ByteSummaryStatistics get() {
            return new ByteSummaryStatistics();
        }
    };

    static final BinaryOperator SummarizingByte_Combiner = new BinaryOperator() {
        @Override
        public ByteSummaryStatistics apply(ByteSummaryStatistics a, ByteSummaryStatistics b) {
            a.combine(b);
            return a;
        }
    };

    static final Supplier SummarizingShort_Supplier = new Supplier() {
        @Override
        public ShortSummaryStatistics get() {
            return new ShortSummaryStatistics();
        }
    };

    static final BinaryOperator SummarizingShort_Combiner = new BinaryOperator() {
        @Override
        public ShortSummaryStatistics apply(ShortSummaryStatistics a, ShortSummaryStatistics b) {
            a.combine(b);
            return a;
        }
    };

    static final Supplier SummarizingInt_Supplier = new Supplier() {
        @Override
        public IntSummaryStatistics get() {
            return new IntSummaryStatistics();
        }
    };

    static final BinaryOperator SummarizingInt_Combiner = new BinaryOperator() {
        @Override
        public IntSummaryStatistics apply(IntSummaryStatistics a, IntSummaryStatistics b) {
            a.combine(b);
            return a;
        }
    };

    static final Supplier SummarizingLong_Supplier = new Supplier() {
        @Override
        public LongSummaryStatistics get() {
            return new LongSummaryStatistics();
        }
    };

    static final BinaryOperator SummarizingLong_Combiner = new BinaryOperator() {
        @Override
        public LongSummaryStatistics apply(LongSummaryStatistics a, LongSummaryStatistics b) {
            a.combine(b);
            return a;
        }
    };

    static final Supplier SummarizingFloat_Supplier = new Supplier() {
        @Override
        public FloatSummaryStatistics get() {
            return new FloatSummaryStatistics();
        }
    };

    static final BinaryOperator SummarizingFloat_Combiner = new BinaryOperator() {
        @Override
        public FloatSummaryStatistics apply(FloatSummaryStatistics a, FloatSummaryStatistics b) {
            a.combine(b);
            return a;
        }
    };

    static final Supplier SummarizingDouble_Supplier = new Supplier() {
        @Override
        public DoubleSummaryStatistics get() {
            return new DoubleSummaryStatistics();
        }
    };

    static final BinaryOperator SummarizingDouble_Combiner = new BinaryOperator() {
        @Override
        public DoubleSummaryStatistics apply(DoubleSummaryStatistics a, DoubleSummaryStatistics b) {
            a.combine(b);
            return a;
        }
    };

    static final Function, Object> Reducing_Finisher_0 = new Function, Object>() {
        @Override
        public Object apply(Holder a) {
            return a.value();
        }
    };

    static final BiConsumer, Object> Reducing_Accumulator = new BiConsumer, Object>() {
        @Override
        public void accept(OptHolder a, Object t) {
            a.accept(t);
        }
    };

    static final BinaryOperator> Reducing_Combiner = new BinaryOperator>() {
        @Override
        public OptHolder apply(OptHolder a, OptHolder b) {
            if (b.present) {
                a.accept(b.value);
            }

            return a;
        }
    };

    static final Function, Optional> Reducing_Finisher = new Function, Optional>() {
        @Override
        public Optional apply(OptHolder a) {
            return a.present ? Optional.of(a.value) : (Optional) Optional.empty();
        }
    };

    static final BiConsumer, Object> Reducing_Accumulator_2 = new BiConsumer, Object>() {
        @Override
        public void accept(MappingOptHolder a, Object t) {
            a.accept(t);
        }
    };

    static final BinaryOperator> Reducing_Combiner_2 = new BinaryOperator>() {
        @Override
        public MappingOptHolder apply(MappingOptHolder a, MappingOptHolder 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 = new Function, Optional>() {
        @Override
        public Optional apply(MappingOptHolder a) {
            return a.present ? Optional.of(a.value) : (Optional) Optional.empty();
        }
    };

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

    Collectors() {
    }

    static class CollectorImpl implements Collector {
        private static final Function IDENTITY_FINISHER = new Function() {
            @Override
            public Object apply(Object t) {
                return 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;
        }
    }

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

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

    public static  Collector> toList() {
        final Supplier> supplier = Suppliers. ofList();

        return toCollection(supplier);
    }

    public static  Collector> toLinkedList() {
        final Supplier> supplier = Suppliers. ofLinkedList();

        return toCollection(supplier);
    }

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

        return collectingAndThen(downstream, finisher);
    }

    public static  Collector> toSet() {
        final Supplier> supplier = Suppliers. ofSet();

        return toCollection(supplier);
    }

    public static  Collector> toLinkedHashSet() {
        final Supplier> supplier = Suppliers. ofLinkedHashSet();

        return toCollection(supplier);
    }

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

        return collectingAndThen(downstream, finisher);
    }

    public static  Collector> toQueue() {
        final Supplier> supplier = Suppliers. ofQueue();

        return toCollection(supplier);
    }

    public static  Collector> toDeque() {
        final Supplier> supplier = Suppliers. ofDeque();

        return toCollection(supplier);
    }

    public static > Collector toCollection(final Supplier collectionFactory, final int atMostSize) {
        final BiConsumer accumulator = new BiConsumer() {
            @Override
            public void accept(C c, T t) {
                if (c.size() < atMostSize) {
                    c.add(t);
                }
            }
        };

        final BinaryOperator combiner = new BinaryOperator() {
            @Override
            public C apply(C a, C 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);
    }

    public static  Collector> toList(final int atMostSize) {
        final Supplier> supplier = new Supplier>() {
            @Override
            public List get() {
                return new ArrayList(N.min(256, atMostSize));
            }
        };

        return toCollection(supplier, atMostSize);
    }

    public static  Collector> toSet(final int atMostSize) {
        final Supplier> supplier = new Supplier>() {
            @Override
            public Set get() {
                return new HashSet(N.initHashCapacity(atMostSize));
            }
        };

        return toCollection(supplier, atMostSize);
    }

    public static  Collector> toMultiset() {
        final Supplier> supplier = Suppliers.ofMultiset();

        return toMultiset(supplier);
    }

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

    public static  Collector> toLongMultiset() {
        final Supplier> supplier = Suppliers.ofLongMultiset();

        return toLongMultiset(supplier);
    }

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

    public static  Collector toArray() {
        return toArray(Suppliers.ofEmptyObjectArray());
    }

    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 = new Function, A[]>() {
            @Override
            public A[] apply(List 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);
    }

    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 = new Function, A[]>() {
            @Override
            public A[] apply(List t) {
                return t.toArray(arraySupplier.apply(t.size()));
            }
        };

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    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 = new Supplier>>() {
        @Override
        public Holder> get() {
            return Holder.of(Optional.empty());
        }
    };

    private static final BiConsumer>, Object> onlyOne_accumulator = new BiConsumer>, Object>() {
        @Override
        public void accept(Holder> holder, Object val) {
            if (holder.value().isPresent()) {
                throw new DuplicatedResultException("Duplicate values");
            }

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

    private static final BinaryOperator>> onlyOne_combiner = new BinaryOperator>>() {
        @Override
        public Holder> apply(Holder> t, Holder> u) {
            if (t.value().isPresent() && u.value().isPresent()) {
                throw new DuplicatedResultException("Duplicate values");
            }

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

    private static final Function>, Optional> onlyOne_finisher = new Function>, Optional>() {
        @Override
        public Optional apply(Holder> t) {
            return t.value();
        }
    };

    /**
     * {@code DuplicatedResultException} is threw if there are more than one values are collected.
     * 
     * @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 DuplicatedResultException} is threw if there are more than one values are collected.
     * 
     * @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 = new Supplier>() {
        @Override
        public Holder get() {
            return Holder.of(NONE);
        }
    };

    private static final BiConsumer, Object> first_accumulator = new BiConsumer, Object>() {
        @Override
        public void accept(Holder holder, Object val) {
            if (holder.value() == NONE) {
                holder.setValue(val);
            }
        }
    };

    private static final BiConsumer, Object> last_accumulator = new BiConsumer, Object>() {
        @Override
        public void accept(Holder holder, Object val) {
            holder.setValue(val);
        }
    };

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

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

    private static final Function, Optional> first_last_finisher = new Function, Optional>() {
        @Override
        public Optional apply(Holder t) {
            return t.value() == NONE ? Optional.empty() : Optional.of(t.value());
        }
    };

    /** 
     * Only works for sequential Stream.
     * 
     * @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.
     * 
     * @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 n
     * @return
     * @throws UnsupportedOperationException operated by multiple threads
     */
    public static  Collector> first(final int n) {
        N.checkArgNotNegative(n, "n");

        final Supplier> supplier = new Supplier>() {
            @Override
            public List get() {
                return new ArrayList(N.min(256, n));
            }
        };

        final BiConsumer, T> accumulator = new BiConsumer, T>() {
            @Override
            public void accept(List c, T t) {
                if (c.size() < n) {
                    c.add(t);
                }
            }
        };

        final BinaryOperator> combiner = new BinaryOperator>() {
            @Override
            public List apply(List a, List 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 n
     * @return
     * @throws UnsupportedOperationException operated by multiple threads
     */
    public static  Collector> last(final int n) {
        N.checkArgNotNegative(n, "n");

        final Supplier> supplier = new Supplier>() {
            @Override
            public Deque get() {
                return n <= 1024 ? new ArrayDeque(n) : new LinkedList();
            }
        };

        final BiConsumer, T> accumulator = new BiConsumer, T>() {
            @Override
            public void accept(Deque dqueue, T t) {
                if (n > 0) {
                    if (dqueue.size() >= n) {
                        dqueue.pollFirst();
                    }

                    dqueue.offerLast(t);
                }
            }
        };

        final BinaryOperator> combiner = new BinaryOperator>() {
            @Override
            public Deque apply(Deque a, Deque 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 = new Function, List>() {
            @Override
            public List apply(Deque dqueue) {
                return new ArrayList<>(dqueue);
            }
        };

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

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

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

    public static Collector joining(final CharSequence delimiter, final CharSequence prefix, final CharSequence suffix) {
        final Supplier supplier = new Supplier() {
            @Override
            public Joiner get() {
                return Joiner.with(delimiter, prefix, suffix).reuseCachedBuffer(true);
            }
        };

        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 = new BiConsumer() { @Override public void accept(A a, T t) { if (predicate.test(t)) { downstreamAccumulator.accept(a, t); } } }; return new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } public static Collector> mapping(Function mapper) { return Collectors.mapping(mapper, Collectors. toList()); } public static Collector mapping(final Function mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = new BiConsumer() { @Override public void accept(A a, T t) { downstreamAccumulator.accept(a, mapper.apply(t)); } }; return new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } public static Collector> flatMapping(final Function> mapper) { return flatMapping(mapper, Collectors. toList()); } public static Collector flatMapping(final Function> mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = new BiConsumer() { @Override public void accept(final A a, final T t) { try (Stream stream = mapper.apply(t)) { final ObjIterator iter = stream.iterator(); while (iter.hasNext()) { downstreamAccumulator.accept(a, iter.next()); } } } }; return new CollectorImpl<>(downstream.supplier(), accumulator, downstream.combiner(), downstream.finisher(), downstream.characteristics()); } public static Collector> flattMapping(final Function> mapper) { return flattMapping(mapper, Collectors. toList()); } public static Collector flattMapping(final Function> mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = new BiConsumer() { @Override public void accept(final A a, final T 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()); } public static Collector> flatMapping(final Function> flatMapper, final BiFunction mapper) { return flatMapping(flatMapper, mapper, Collectors. toList()); } public static Collector flatMapping(final Function> flatMapper, final BiFunction mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = new BiConsumer() { @Override public void accept(final A a, final T t) { try (Stream stream = flatMapper.apply(t)) { final ObjIterator 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()); } public static Collector> flattMapping(final Function> flatMapper, final BiFunction mapper) { return flattMapping(flatMapper, mapper, Collectors. toList()); } public static Collector flattMapping(final Function> flatMapper, final BiFunction mapper, final Collector downstream) { final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer accumulator = new BiConsumer() { @Override public void accept(final A a, final T 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()); } public static Collector collectingAndThen(final Collector downstream, final Function finisher) { N.checkArgNotNull(finisher); final Function downstreamFinisher = downstream.finisher(); final Function thenFinisher = new Function() { @Override public RR apply(A t) { return 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); } public static Collector collectingAndThen(final java.util.stream.Collector downstream, final java.util.function.Function finisher) { N.checkArgNotNull(downstream); N.checkArgNotNull(finisher); return collectingAndThen(Collector.from(downstream), r -> finisher.apply(r)); } /** * 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 mapper 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 mapper) { @SuppressWarnings("rawtypes") final Supplier> supplier = (Supplier) Suppliers. ofLinkedHashMap(); final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Map map, T t) { final Object key = mapper.apply(t); if (map.containsKey(key) == false) { map.put(key, t); } } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Map apply(Map a, Map b) { for (Map.Entry entry : b.entrySet()) { if (a.containsKey(entry.getKey()) == false) { a.put(entry.getKey(), entry.getValue()); } } return a; } }; final Function, List> finisher = new Function, List>() { @Override public List apply(Map map) { return new ArrayList<>(map.values()); } }; 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 mapper 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(Function mapper) { final Collector> downstream = Collectors.toSet(); final Function, Integer> finisher = new Function, Integer>() { @Override public Integer apply(Set t) { return t.size(); } }; return Collectors.collectingAndThen(Collectors.mapping(mapper, downstream), finisher); } public static Collector counting() { final Function accumulator = Counting_Accumulator; final BinaryOperator combiner = Counting_Combiner; return reducing(0L, accumulator, combiner); } public static Collector countingInt() { final Function accumulator = CountingInt_Accumulator; final BinaryOperator combiner = CountingInt_Combiner; return reducing(0, accumulator, combiner); } @SuppressWarnings("rawtypes") public static Collector> min() { return minBy(Fn.naturalOrder()); } public static Collector> minBy(final Comparator comparator) { N.checkArgNotNull(comparator); final BinaryOperator op = new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) <= 0 ? a : b; } }; return reducing(op); } public static Collector minByOrGet(final Comparator comparator, final Supplier other) { N.checkArgNotNull(comparator); final BinaryOperator op = new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) <= 0 ? a : b; } }; return reducingOrGet(op, other); } public static Collector minByOrThrow(final Comparator comparator, final Supplier exceptionSupplier) { N.checkArgNotNull(comparator); final BinaryOperator op = new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) <= 0 ? a : b; } }; return reducingOrThrow(op, exceptionSupplier); } @SuppressWarnings("rawtypes") public static Collector> max() { return maxBy(Fn.naturalOrder()); } public static Collector> maxBy(final Comparator comparator) { N.checkArgNotNull(comparator); final BinaryOperator op = new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) >= 0 ? a : b; } }; return reducing(op); } public static Collector maxByOrGet(final Comparator comparator, final Supplier other) { N.checkArgNotNull(comparator); final BinaryOperator op = new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) >= 0 ? a : b; } }; return reducingOrGet(op, other); } public static Collector maxByOrThrow(final Comparator comparator, final Supplier exceptionSupplier) { N.checkArgNotNull(comparator); final BinaryOperator op = new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) >= 0 ? a : b; } }; return reducingOrThrow(op, exceptionSupplier); } /** * * @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 = new BiFunction, Optional, Optional>() { @Override public Optional apply(Optional min, Optional max) { return min.isPresent() ? Optional.of((R) finisher.apply(min.get(), max.get())) : Optional. empty(); } }; return combine(Collectors.minBy(comparator), Collectors.maxBy(comparator), finisher2); } /** * 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) */ @SuppressWarnings("rawtypes") public static Collector> maxAll() { return maxAll(Fn.naturalOrder()); } /** * 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 comparator * @param atMostSize * @return */ public static Collector> maxAll(final Comparator comparator, final int atMostSize) { final Supplier>> supplier = new Supplier>>() { @Override public Pair> get() { final List list = new ArrayList(Math.min(16, atMostSize)); return Pair.of((T) NONE, list); } }; final BiConsumer>, T> accumulator = new BiConsumer>, T>() { @Override public void accept(Pair> a, T 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) { if (a.right.size() < atMostSize) { a.right.add(t); } } } } }; final BinaryOperator>> combiner = new BinaryOperator>>() { @Override public Pair> apply(Pair> a, Pair> 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 = new Function>, List>() { @Override public List apply(Pair> a) { return a.right; } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } /** * Use occurrences to save the count of largest objects if {@code areAllLargestSame = true}(e.g. {@code Number/String/...}) and return a list by repeat the largest object {@code n} times. * * @param areAllLargestSame * @return * @see Collectors#maxAll(Comparator, int, boolean) */ @SuppressWarnings("rawtypes") public static Collector> maxAll(final boolean areAllLargestSame) { return maxAll(Integer.MAX_VALUE, areAllLargestSame); } /** * Use occurrences to save the count of largest objects if {@code areAllLargestSame = true}(e.g. {@code Number/String/...}) and return a list by repeat the largest object {@code n} times. * * @param atMostSize * @param areAllLargestSame * @return * @see Collectors#maxAll(Comparator, int, boolean) */ @SuppressWarnings("rawtypes") public static Collector> maxAll(final int atMostSize, final boolean areAllLargestSame) { return maxAll(Fn.naturalOrder(), atMostSize, areAllLargestSame); } /** * Use occurrences to save the count of largest objects if {@code areAllLargestSame = true}(e.g. {@code Number/String/...}) and return a list by repeat the largest object {@code n} times. * * @implSpec * The default implementation is equivalent to, for this {@code map}: *

 
     * 
     * if (areAllLargestSame) {
     *     final Function, Integer>, List> finisher = new Function, Integer>, List>() {
     *        @Override
     *        public List apply(Pair, Integer> t) {
     *            int n = N.min(atMostSize, t.right.intValue());
     *            return n == 0 ? new ArrayList() : N.repeat(t.left.get(), n);
     *        }
     *     };
     *
     *     return maxAlll(comparator, countingInt(), finisher);
     * } else {
     *     return maxAll(comparator, atMostSize);
     * }
     * 
     * 
* @param atMostSize * @param areAllLargestSame * @return */ public static Collector> maxAll(final Comparator comparator, final int atMostSize, final boolean areAllLargestSame) { N.checkArgPositive(atMostSize, "atMostSize"); if (areAllLargestSame) { final Function, Integer>, List> finisher = new Function, Integer>, List>() { @Override public List apply(Pair, Integer> t) { int n = N.min(atMostSize, t.right.intValue()); return n == 0 ? new ArrayList() : N.repeat(t.left.get(), n); } }; return maxAlll(comparator, countingInt(), finisher); } else { return maxAll(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 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.naturalOrder(), 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, T>() { @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 = new BinaryOperator>() { @Override public Pair apply(Pair a, Pair 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 = new Function, D>() { @Override public D apply(Pair t) { return downstream.finisher().apply(t.right); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } @SuppressWarnings("unchecked") static T none() { return (T) NONE; } @SuppressWarnings("rawtypes") public static Collector, D>> maxAlll(Collector downstream) { return maxAlll(Fn.naturalOrder(), downstream); } public static Collector, D>> maxAlll(final Comparator comparator, final Collector downstream) { return maxAlll(comparator, downstream, Fn., D>> identity()); } public static Collector maxAlll(final Comparator comparator, final Collector downstream, final Function, D>, 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, T>() { @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 = new BinaryOperator>() { @Override public Pair apply(Pair a, Pair 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 = new Function, R>() { @Override public R apply(Pair a) { @SuppressWarnings("rawtypes") final Pair, D> result = (Pair) a; result.setLeft(a.left == NONE ? Optional. empty() : Optional.of(a.left)); result.setRight(downstream.finisher().apply(a.right)); return finisher.apply(result); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, 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 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) */ @SuppressWarnings("rawtypes") public static Collector> minAll() { return minAll(Fn.naturalOrder()); } /** * 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 comparator * @param atMostSize * @return */ public static Collector> minAll(Comparator comparator, int atMostSize) { return maxAll(Fn.reversedOrder(comparator), atMostSize); } /** * Use occurrences to save the count of largest objects if {@code areAllSmallestSame = true}(e.g. {@code Number/String/...}) and return a list by repeat the smallest object {@code n} times. * * @param areAllSmallestSame * @return * @see Collectors#maxAll(Comparator, int, boolean) */ @SuppressWarnings("rawtypes") public static Collector> minAll(final boolean areAllSmallestSame) { return minAll(Integer.MAX_VALUE, areAllSmallestSame); } /** * Use occurrences to save the count of largest objects if {@code areAllSmallestSame = true}(e.g. {@code Number/String/...}) and return a list by repeat the smallest object {@code n} times. * * @param atMostSize * @param areAllSmallestSame * @return * @see Collectors#maxAll(Comparator, int, boolean) */ @SuppressWarnings("rawtypes") public static Collector> minAll(final int atMostSize, final boolean areAllSmallestSame) { return minAll(Fn.naturalOrder(), atMostSize, areAllSmallestSame); } /** * Use occurrences to save the count of largest objects if {@code areAllSmallestSame = true}(e.g. {@code Number/String/...}) and return a list by repeat the smallest object {@code n} times. * * @param comparator * @param atMostSize * @param areAllSmallestSame * @return * @see Collectors#maxAll(Comparator, int, boolean) */ public static Collector> minAll(final Comparator comparator, final int atMostSize, final boolean areAllSmallestSame) { return maxAll(Fn.reversedOrder(comparator), atMostSize, areAllSmallestSame); } /** * 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.naturalOrder(), 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); } @SuppressWarnings("rawtypes") public static Collector, D>> minAlll(Collector downstream) { return minAlll(Fn.naturalOrder(), downstream); } public static Collector, D>> minAlll(final Comparator comparator, final Collector downstream) { return minAlll(comparator, downstream, Fn., D>> identity()); } public static Collector minAlll(final Comparator comparator, final Collector downstream, final Function, D>, R> finisher) { return maxAlll(Fn.reversedOrder(comparator), downstream, finisher); } public static Collector summingInt(final ToIntFunction mapper) { final Supplier supplier = SummingInt_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsInt(t); } }; final BinaryOperator combiner = SummingInt_Combiner; final Function finisher = SummingInt_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summingIntt(final ToIntFunction mapper) { final Supplier supplier = SummingInt_Supplier_2; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsInt(t); } }; final BinaryOperator combiner = SummingInt_Combiner_2; final Function finisher = SummingInt_Finisher_2; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summingLong(final ToLongFunction mapper) { final Supplier supplier = SummingLong_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsLong(t); } }; final BinaryOperator combiner = SummingLong_Combiner; final Function finisher = SummingLong_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summingLongg(final ToLongFunction mapper) { final Supplier supplier = SummingLong_Supplier_2; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsLong(t); } }; final BinaryOperator combiner = SummingLong_Combiner_2; final Function finisher = SummingLong_Finisher_2; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summingDouble(final ToDoubleFunction mapper) { final Supplier supplier = SummingDouble_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(KahanSummation a, T t) { a.add(mapper.applyAsDouble(t)); } }; final BinaryOperator combiner = SummingDouble_Combiner; final Function finisher = SummingDouble_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summingDoubble(final ToDoubleFunction mapper) { final Supplier supplier = SummingDouble_Supplier_2; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(KahanSummation a, T t) { a.add(mapper.applyAsDouble(t)); } }; final BinaryOperator combiner = SummingDouble_Combiner_2; final Function finisher = SummingDouble_Finisher_2; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summingBigInteger(final Function mapper) { final Supplier supplier = SummingBigInteger_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(BigInteger[] a, T t) { a[0] = a[0].add(mapper.apply(t)); } }; final BinaryOperator combiner = SummingBigInteger_Combiner; final Function finisher = SummingBigInteger_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summingBigDecimal(final Function mapper) { final Supplier supplier = SummingBigDecimal_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(BigDecimal[] a, T t) { a[0] = a[0].add(mapper.apply(t)); } }; final BinaryOperator combiner = SummingBigDecimal_Combiner; final Function finisher = SummingBigDecimal_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingInt(final ToIntFunction mapper) { final Supplier supplier = AveragingInt_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsInt(t); a[1]++; } }; final BinaryOperator combiner = AveragingInt_Combiner; final Function finisher = AveragingInt_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingIntt(final ToIntFunction mapper) { final Supplier supplier = AveragingInt_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsInt(t); a[1]++; } }; final BinaryOperator combiner = AveragingInt_Combiner; final Function finisher = AveragingInt_Finisher_2; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingLong(final ToLongFunction mapper) { final Supplier supplier = AveragingLong_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsLong(t); a[1]++; } }; final BinaryOperator combiner = AveragingLong_Combiner; final Function finisher = AveragingLong_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingLongg(final ToLongFunction mapper) { final Supplier supplier = AveragingLong_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(long[] a, T t) { a[0] += mapper.applyAsLong(t); a[1]++; } }; final BinaryOperator combiner = AveragingLong_Combiner; final Function finisher = AveragingLong_Finisher_2; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingDouble(final ToDoubleFunction mapper) { final Supplier supplier = AveragingDouble_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(KahanSummation a, T t) { a.add(mapper.applyAsDouble(t)); } }; final BinaryOperator combiner = AveragingDouble_Combiner; final Function finisher = AveragingDouble_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingDoubble(final ToDoubleFunction mapper) { final Supplier supplier = AveragingDouble_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(KahanSummation a, T t) { a.add(mapper.applyAsDouble(t)); } }; final BinaryOperator combiner = AveragingDouble_Combiner; final Function finisher = AveragingDouble_Finisher_2; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingBigInteger(final Function mapper) { final Supplier> supplier = AveragingBigInteger_Supplier; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Pair a, T t) { a.setLeft(a.left.add(mapper.apply(t))); a.right.increment(); } }; final BinaryOperator> combiner = AveragingBigInteger_Combiner; final Function, BigDecimal> finisher = AveragingBigInteger_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector averagingBigDecimal(final Function mapper) { final Supplier> supplier = AveragingBigDecimal_Supplier; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Pair a, T t) { a.setLeft(a.left.add(mapper.apply(t))); a.right.increment(); } }; final BinaryOperator> combiner = AveragingBigDecimal_Combiner; final Function, BigDecimal> finisher = AveragingBigDecimal_Finisher; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector summarizingChar(final ToCharFunction mapper) { final Supplier supplier = SummarizingChar_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(CharSummaryStatistics a, T t) { a.accept(mapper.applyAsChar(t)); } }; final BinaryOperator combiner = SummarizingChar_Combiner; return new CollectorImpl(supplier, accumulator, combiner, CH_UNORDERED_ID); } public static Collector summarizingByte(final ToByteFunction mapper) { final Supplier supplier = SummarizingByte_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(ByteSummaryStatistics a, T t) { a.accept(mapper.applyAsByte(t)); } }; final BinaryOperator combiner = SummarizingByte_Combiner; return new CollectorImpl(supplier, accumulator, combiner, CH_UNORDERED_ID); } public static Collector summarizingShort(final ToShortFunction mapper) { final Supplier supplier = SummarizingShort_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(ShortSummaryStatistics a, T t) { a.accept(mapper.applyAsShort(t)); } }; final BinaryOperator combiner = SummarizingShort_Combiner; return new CollectorImpl(supplier, accumulator, combiner, CH_UNORDERED_ID); } public static Collector summarizingInt(final ToIntFunction mapper) { final Supplier supplier = SummarizingInt_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(IntSummaryStatistics a, T t) { a.accept(mapper.applyAsInt(t)); } }; final BinaryOperator combiner = SummarizingInt_Combiner; return new CollectorImpl(supplier, accumulator, combiner, CH_UNORDERED_ID); } public static Collector summarizingLong(final ToLongFunction mapper) { final Supplier supplier = SummarizingLong_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(LongSummaryStatistics a, T t) { a.accept(mapper.applyAsLong(t)); } }; final BinaryOperator combiner = SummarizingLong_Combiner; return new CollectorImpl(supplier, accumulator, combiner, CH_UNORDERED_ID); } public static Collector summarizingFloat(final ToFloatFunction mapper) { final Supplier supplier = SummarizingFloat_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(FloatSummaryStatistics a, T t) { a.accept(mapper.applyAsFloat(t)); } }; final BinaryOperator combiner = SummarizingFloat_Combiner; return new CollectorImpl(supplier, accumulator, combiner, CH_UNORDERED_ID); } public static Collector summarizingDouble(final ToDoubleFunction mapper) { final Supplier supplier = SummarizingDouble_Supplier; final BiConsumer accumulator = new BiConsumer() { @Override public void accept(DoubleSummaryStatistics a, T t) { a.accept(mapper.applyAsDouble(t)); } }; final BinaryOperator combiner = SummarizingDouble_Combiner; return new CollectorImpl(supplier, accumulator, combiner, CH_UNORDERED_ID); } public static Collector reducing(final T identity, final BinaryOperator op) { final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Holder a, T t) { a.setValue(op.apply(a.value(), t)); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Holder apply(Holder a, Holder 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); } @SuppressWarnings("rawtypes") public static Collector> reducing(final BinaryOperator op) { final Supplier> supplier = new Supplier>() { @Override public OptHolder get() { return 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); } @SuppressWarnings("rawtypes") public static Collector reducingOrGet(final BinaryOperator op, final Supplier other) { final Supplier> supplier = new Supplier>() { @Override public OptHolder get() { return new OptHolder(op); } }; final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner; final Function, T> finisher = new Function, T>() { @Override public T apply(OptHolder a) { return a.present ? a.value : other.get(); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } @SuppressWarnings("rawtypes") public static Collector reducingOrThrow(final BinaryOperator op, final Supplier exceptionSupplier) { final Supplier> supplier = new Supplier>() { @Override public OptHolder get() { return new OptHolder(op); } }; final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner; final Function, T> finisher = new Function, T>() { @Override public T apply(OptHolder a) { if (a.present) { return a.value; } else { throw exceptionSupplier.get(); } } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector reducing(final U identity, final Function mapper, final BinaryOperator op) { final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Holder a, T t) { a.setValue(op.apply(a.value(), mapper.apply(t))); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Holder apply(Holder a, Holder 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); } @SuppressWarnings("rawtypes") public static Collector> reducing(final Function mapper, final BinaryOperator op) { final Supplier> supplier = new Supplier>() { @Override public MappingOptHolder get() { return 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 new Supplier>() { @Override public Holder get() { 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; } } } @SuppressWarnings("rawtypes") public static Collector reducingOrGet(final Function mapper, final BinaryOperator op, final Supplier other) { final Supplier> supplier = new Supplier>() { @Override public MappingOptHolder get() { return new MappingOptHolder(mapper, op); } }; final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator_2; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner_2; final Function, U> finisher = new Function, U>() { @Override public U apply(MappingOptHolder a) { return a.present ? a.value : other.get(); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, CH_UNORDERED_NOID); } @SuppressWarnings("rawtypes") public static Collector reducingOrThrow(final Function mapper, final BinaryOperator op, final Supplier exceptionSupplier) { final Supplier> supplier = new Supplier>() { @Override public MappingOptHolder get() { return new MappingOptHolder(mapper, op); } }; final BiConsumer, T> accumulator = (BiConsumer) Reducing_Accumulator_2; final BinaryOperator> combiner = (BinaryOperator) Reducing_Combiner_2; final Function, U> finisher = new Function, U>() { @Override public U apply(MappingOptHolder a) { if (a.present) { return a.value; } else { throw exceptionSupplier.get(); } } }; 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 prefix of input * {@code CharSequence} objects returning the result as {@code String}. For * empty input the empty {@code String} is returned. * *

* 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 = new Supplier>() { @Override public Pair get() { return Pair.of(null, -1); } }; final BiConsumer, CharSequence> accumulator = new BiConsumer, CharSequence>() { @Override public void accept(Pair a, CharSequence 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 = new BinaryOperator>() { @Override public Pair apply(Pair a, Pair 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 = new Function, String>() { @Override public String apply(Pair a) { return 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 = new Supplier>() { @Override public Pair get() { return Pair.of(null, -1); } }; final BiConsumer, CharSequence> accumulator = new BiConsumer, CharSequence>() { @Override public void accept(Pair a, CharSequence 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 = new BinaryOperator>() { @Override public Pair apply(Pair a, Pair 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 = new Function, String>() { @Override public String apply(Pair a) { return 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); } public static Collector>> groupingBy(Function keyMapper) { final Collector> downstream = toList(); return groupingBy(keyMapper, downstream); } public static >> Collector groupingBy(final Function keyMapper, final Supplier mapFactory) { final Collector> downstream = toList(); return groupingBy(keyMapper, downstream, mapFactory); } public static Collector> groupingBy(final Function keyMapper, final Collector downstream) { final Supplier> mapFactory = Suppliers.ofMap(); return groupingBy(keyMapper, downstream, mapFactory); } 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 = new Function() { @Override public A apply(K k) { return downstreamSupplier.get(); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Map m, T 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 = new BiFunction() { @Override public A apply(K k, A v) { return downstreamFinisher.apply(v); } }; final Function, M> finisher = new Function, M>() { @Override public M apply(Map intermediate) { replaceAll(intermediate, function); @SuppressWarnings("unchecked") M castResult = (M) intermediate; return castResult; } }; return new CollectorImpl<>(mangledFactory, accumulator, combiner, finisher, CH_UNORDERED_NOID); } public static Collector>> groupingByConcurrent(Function keyMapper) { final Collector> downstream = toList(); return groupingByConcurrent(keyMapper, downstream); } public static >> Collector groupingByConcurrent(final Function keyMapper, final Supplier mapFactory) { final Collector> downstream = toList(); return groupingByConcurrent(keyMapper, downstream, mapFactory); } public static Collector> groupingByConcurrent(Function keyMapper, Collector downstream) { final Supplier> mapFactory = Suppliers.ofConcurrentMap(); return groupingByConcurrent(keyMapper, downstream, mapFactory); } 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 = new Function() { @Override public A apply(K k) { return downstreamSupplier.get(); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(ConcurrentMap m, T 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 = new BiFunction() { @Override public A apply(K k, A v) { return downstreamFinisher.apply(v); } }; final Function, M> finisher = new Function, M>() { @Override public M apply(ConcurrentMap intermediate) { replaceAll(intermediate, function); @SuppressWarnings("unchecked") M castResult = (M) intermediate; return castResult; } }; return new CollectorImpl<>(mangledFactory, accumulator, combiner, finisher, CH_UNORDERED_NOID); } } public static Collector>> partitioningBy(Predicate predicate) { final Collector> downstream = toList(); return partitioningBy(predicate, downstream); } public static Collector> partitioningBy(final Predicate predicate, final Collector downstream) { final Supplier> supplier = new Supplier>() { @Override public Map get() { final Map map = new HashMap<>(2); map.put(true, downstream.supplier().get()); map.put(false, downstream.supplier().get()); return map; } }; final BiConsumer downstreamAccumulator = downstream.accumulator(); final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Map a, T t) { downstreamAccumulator.accept(predicate.test(t) ? a.get(Boolean.TRUE) : a.get(Boolean.FALSE), t); } }; final BinaryOperator op = downstream.combiner(); final BinaryOperator> combiner = new BinaryOperator>() { @Override public Map apply(Map a, Map 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 = new Function, Map>() { @Override public Map apply(Map 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); } public static Collector, ?, Map> toMap() { final Function, ? extends K> keyMapper = Fn. key(); final Function, ? extends V> valueMapper = Fn. value(); return toMap(keyMapper, valueMapper); } 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); } 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); } 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); } public static Collector> toMap(Function keyMapper, Function valueMapper) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toMap(keyMapper, valueMapper, mergeFunction); } public static Collector> toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) { final Supplier> mapFactory = Suppliers. ofMap(); return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } public static > Collector toMap(final Function keyMapper, final Function valueMapper, final Supplier mapFactory) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } public static > Collector toMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, final Supplier mapFactory) { final BiConsumer accumulator = new BiConsumer() { @Override public void accept(M map, T 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 keyMapper * @param downstream * @return * @see Collectors#groupingBy(Function, Collector) */ public static Collector> toMap(final Function keyMapper, final Collector downstream) { return groupingBy(keyMapper, downstream); } /** * * @param keyMapper * @param downstream * @param mapFactory * @return * @see Collectors#groupingBy(Function, Collector, Supplier) */ public static > Collector toMap(final Function keyMapper, final Collector downstream, final Supplier mapFactory) { return groupingBy(keyMapper, downstream, mapFactory); } /** * * @param keyMapper * @param valueMapper * @param downstream * @return * @see Collectors#groupingBy(Function, Collector) */ public static Collector> toMap(final Function keyMapper, final Function valueMapper, final Collector downstream) { return groupingBy(keyMapper, mapping(valueMapper, downstream)); } /** * * @param keyMapper * @param valueMapper * @param downstream * @param mapFactory * @return * @see Collectors#groupingBy(Function, Collector, Supplier) */ public static > Collector toMap(final Function keyMapper, final Function valueMapper, final Collector downstream, final Supplier mapFactory) { return groupingBy(keyMapper, mapping(valueMapper, downstream), mapFactory); } public static Collector, ?, ImmutableMap> toImmutableMap() { final Collector, ?, Map> downstream = toMap(); @SuppressWarnings("rawtypes") final Function, ImmutableMap> finisher = (Function) ImmutableMap_Finisher; return collectingAndThen(downstream, finisher); } 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); } 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); } 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 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 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); } public static Collector> toConcurrentMap(Function keyMapper, Function valueMapper) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toConcurrentMap(keyMapper, valueMapper, mergeFunction); } public static > Collector toConcurrentMap(final Function keyMapper, final Function valueMapper, Supplier mapFactory) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toConcurrentMap(keyMapper, valueMapper, mergeFunction, mapFactory); } public static Collector> toConcurrentMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) { final Supplier> mapFactory = Suppliers.ofConcurrentMap(); return toConcurrentMap(keyMapper, valueMapper, mergeFunction, mapFactory); } public static > Collector toConcurrentMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, Supplier mapFactory) { final BiConsumer accumulator = new BiConsumer() { @Override public void accept(M map, T 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); } public static Collector> toBiMap(Function keyMapper, Function valueMapper) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toBiMap(keyMapper, valueMapper, mergeFunction); } public static Collector> toBiMap(final Function keyMapper, final Function valueMapper, final Supplier> mapFactory) { final BinaryOperator mergeFunction = Fn.throwingMerger(); return toBiMap(keyMapper, valueMapper, mergeFunction, mapFactory); } public static Collector> toBiMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) { final Supplier> mapFactory = Suppliers.ofBiMap(); return toBiMap(keyMapper, valueMapper, mergeFunction, mapFactory); } public static Collector> toBiMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, final Supplier> mapFactory) { return toMap(keyMapper, valueMapper, mergeFunction, mapFactory); } @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); } @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); } public static Collector> toMultimap(Function keyMapper) { final Function valueMapper = Fn.identity(); return toMultimap(keyMapper, valueMapper); } public static , M extends Multimap> Collector toMultimap(final Function keyMapper, final Supplier mapFactory) { final Function valueMapper = Fn.identity(); return toMultimap(keyMapper, valueMapper, mapFactory); } public static Collector> toMultimap(Function keyMapper, Function valueMapper) { final Supplier> mapFactory = Suppliers.ofListMultimap(); return toMultimap(keyMapper, valueMapper, mapFactory); } public static , M extends Multimap> Collector toMultimap( final Function keyMapper, final Function valueMapper, final Supplier mapFactory) { final BiConsumer accumulator = new BiConsumer() { @Override public void accept(M map, T element) { map.put(keyMapper.apply(element), valueMapper.apply(element)); } }; final BinaryOperator combiner = Collectors. multimapMerger(); return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_UNORDERED_ID); } public static Collector toDataSet() { return toDataSet(null); } public static Collector toDataSet(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(columnNames, t); } }; return new CollectorImpl, DataSet>(collector.supplier(), collector.accumulator(), collector.combiner(), finisher, CH_NOID); } 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 = new Supplier>() { @Override public Tuple2 get() { return Tuple.of(supplier1.get(), supplier2.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple2 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple2 apply(Tuple2 t, Tuple2 u) { return 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 : new HashSet<>(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, Tuple2> finisher = new Function, Tuple2>() { @Override public Tuple2 apply(Tuple2 t) { return Tuple.of(finisher1.apply(t._1), finisher2.apply(t._2)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } 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 = new Supplier>() { @Override public Tuple2 get() { return Tuple.of(supplier1.get(), supplier2.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple2 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple2 apply(Tuple2 t, Tuple2 u) { return 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 : new HashSet<>(common); final Function, R> finalFinisher = new Function, R>() { @Override public R apply(Tuple2 t) { return finisher.apply(finisher1.apply(t._1), finisher2.apply(t._2)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, characteristics); } 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 = new Supplier>() { @Override public Tuple3 get() { return Tuple.of(supplier1.get(), supplier2.get(), supplier3.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple3 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); accumulator3.accept(acct._3, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple3 apply(Tuple3 t, Tuple3 u) { return 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 : new HashSet<>(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, Tuple3> finisher = new Function, Tuple3>() { @Override public Tuple3 apply(Tuple3 t) { return Tuple.of(finisher1.apply(t._1), finisher2.apply(t._2), finisher3.apply(t._3)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } 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 = new Supplier>() { @Override public Tuple3 get() { return Tuple.of(supplier1.get(), supplier2.get(), supplier3.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple3 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); accumulator3.accept(acct._3, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple3 apply(Tuple3 t, Tuple3 u) { return 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 : new HashSet<>(common); final Function, R> finalFinisher = new Function, R>() { @Override public R apply(Tuple3 t) { return finisher.apply(finisher1.apply(t._1), finisher2.apply(t._2), finisher3.apply(t._3)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, characteristics); } @SuppressWarnings("rawtypes") public static Collector, Tuple4> combine( final Collector collector1, final Collector collector2, final Collector collector3, final Collector collector4) { final List> collectors = (List) N.asList(collector1, collector2, collector3, collector4); final Function, Tuple4> func = new Function, Tuple4>() { @Override public Tuple4 apply(List t) { return Tuple4.from(t); } }; return (Collector) collectingAndThen(combine(collectors), func); } @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) N.asList(collector1, collector2, collector3, collector4, collector5); final Function, Tuple5> func = new Function, Tuple5>() { @Override public Tuple5 apply(List t) { return Tuple5.from(t); } }; return (Collector) collectingAndThen(combine(collectors), func); } /** * * @param collectors * @return * @see Tuple#from(Collection) */ @SuppressWarnings("rawtypes") public static Collector> combine(final List> collectors) { N.checkArgument(N.notNullOrEmpty(collectors), "The specified 'collectors' can't be null or empty"); final int len = collectors.size(); final Collector[] cs = collectors.toArray(new Collector[len]); final Supplier> supplier = new Supplier>() { @Override public List get() { final List res = new ArrayList<>(len); for (int i = 0; i < len; i++) { res.add(cs[i].supplier().get()); } return res; } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(List acct, T e) { for (int i = 0; i < len; i++) { cs[i].accumulator().accept(acct.get(i), e); } } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public List apply(List t, List u) { for (int i = 0; i < len; i++) { t.set(i, cs[i].combiner().apply(t.get(i), u.get(i))); } return t; } }; 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 : new HashSet<>(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, List> finisher = new Function, List>() { @Override public List apply(List t) { for (int i = 0; i < len; i++) { t.set(i, cs[i].finisher().apply(t.get(i))); } return t; } }; return (Collector) new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } public static Collector, Tuple2> combine(final java.util.stream.Collector collector1, final java.util.stream.Collector collector2) { final java.util.function.Supplier supplier1 = collector1.supplier(); final java.util.function.Supplier supplier2 = collector2.supplier(); final java.util.function.BiConsumer accumulator1 = collector1.accumulator(); final java.util.function.BiConsumer accumulator2 = collector2.accumulator(); final java.util.function.BinaryOperator combiner1 = collector1.combiner(); final java.util.function.BinaryOperator combiner2 = collector2.combiner(); final java.util.function.Function finisher1 = collector1.finisher(); final java.util.function.Function finisher2 = collector2.finisher(); final Supplier> supplier = new Supplier>() { @Override public Tuple2 get() { return Tuple.of(supplier1.get(), supplier2.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple2 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple2 apply(Tuple2 t, Tuple2 u) { return 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 : new HashSet<>(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, Tuple2> finisher = new Function, Tuple2>() { @Override public Tuple2 apply(Tuple2 t) { return Tuple.of(finisher1.apply(t._1), finisher2.apply(t._2)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } public static Collector, R> combine(final java.util.stream.Collector collector1, final java.util.stream.Collector collector2, final java.util.function.BiFunction finisher) { final java.util.function.Supplier supplier1 = collector1.supplier(); final java.util.function.Supplier supplier2 = collector2.supplier(); final java.util.function.BiConsumer accumulator1 = collector1.accumulator(); final java.util.function.BiConsumer accumulator2 = collector2.accumulator(); final java.util.function.BinaryOperator combiner1 = collector1.combiner(); final java.util.function.BinaryOperator combiner2 = collector2.combiner(); final java.util.function.Function finisher1 = collector1.finisher(); final java.util.function.Function finisher2 = collector2.finisher(); final Supplier> supplier = new Supplier>() { @Override public Tuple2 get() { return Tuple.of(supplier1.get(), supplier2.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple2 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple2 apply(Tuple2 t, Tuple2 u) { return 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 : new HashSet<>(common); final Function, R> finalFinisher = new Function, R>() { @Override public R apply(Tuple2 t) { return finisher.apply(finisher1.apply(t._1), finisher2.apply(t._2)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, characteristics); } public static Collector, Tuple3> combine( final java.util.stream.Collector collector1, final java.util.stream.Collector collector2, final java.util.stream.Collector collector3) { final java.util.function.Supplier supplier1 = collector1.supplier(); final java.util.function.Supplier supplier2 = collector2.supplier(); final java.util.function.Supplier supplier3 = collector3.supplier(); final java.util.function.BiConsumer accumulator1 = collector1.accumulator(); final java.util.function.BiConsumer accumulator2 = collector2.accumulator(); final java.util.function.BiConsumer accumulator3 = collector3.accumulator(); final java.util.function.BinaryOperator combiner1 = collector1.combiner(); final java.util.function.BinaryOperator combiner2 = collector2.combiner(); final java.util.function.BinaryOperator combiner3 = collector3.combiner(); final java.util.function.Function finisher1 = collector1.finisher(); final java.util.function.Function finisher2 = collector2.finisher(); final java.util.function.Function finisher3 = collector3.finisher(); final Supplier> supplier = new Supplier>() { @Override public Tuple3 get() { return Tuple.of(supplier1.get(), supplier2.get(), supplier3.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple3 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); accumulator3.accept(acct._3, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple3 apply(Tuple3 t, Tuple3 u) { return 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 : new HashSet<>(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, Tuple3> finisher = new Function, Tuple3>() { @Override public Tuple3 apply(Tuple3 t) { return Tuple.of(finisher1.apply(t._1), finisher2.apply(t._2), finisher3.apply(t._3)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } public static Collector, R> combine(final java.util.stream.Collector collector1, final java.util.stream.Collector collector2, final java.util.stream.Collector collector3, final TriFunction finisher) { final java.util.function.Supplier supplier1 = collector1.supplier(); final java.util.function.Supplier supplier2 = collector2.supplier(); final java.util.function.Supplier supplier3 = collector3.supplier(); final java.util.function.BiConsumer accumulator1 = collector1.accumulator(); final java.util.function.BiConsumer accumulator2 = collector2.accumulator(); final java.util.function.BiConsumer accumulator3 = collector3.accumulator(); final java.util.function.BinaryOperator combiner1 = collector1.combiner(); final java.util.function.BinaryOperator combiner2 = collector2.combiner(); final java.util.function.BinaryOperator combiner3 = collector3.combiner(); final java.util.function.Function finisher1 = collector1.finisher(); final java.util.function.Function finisher2 = collector2.finisher(); final java.util.function.Function finisher3 = collector3.finisher(); final Supplier> supplier = new Supplier>() { @Override public Tuple3 get() { return Tuple.of(supplier1.get(), supplier2.get(), supplier3.get()); } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(Tuple3 acct, T e) { accumulator1.accept(acct._1, e); accumulator2.accept(acct._2, e); accumulator3.accept(acct._3, e); } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public Tuple3 apply(Tuple3 t, Tuple3 u) { return 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 : new HashSet<>(common); final Function, R> finalFinisher = new Function, R>() { @Override public R apply(Tuple3 t) { return finisher.apply(finisher1.apply(t._1), finisher2.apply(t._2), finisher3.apply(t._3)); } }; return new CollectorImpl<>(supplier, accumulator, combiner, finalFinisher, characteristics); } @SuppressWarnings("rawtypes") public static Collector, Tuple4> combine( final java.util.stream.Collector collector1, final java.util.stream.Collector collector2, final java.util.stream.Collector collector3, final java.util.stream.Collector collector4) { final List> collectors = (List) N.asList(collector1, collector2, collector3, collector4); final Function, Tuple4> func = new Function, Tuple4>() { @Override public Tuple4 apply(List t) { return Tuple4.from(t); } }; return (Collector) collectingAndThen(combine(collectors), func); } @SuppressWarnings("rawtypes") public static Collector, Tuple5> combine( final java.util.stream.Collector collector1, final java.util.stream.Collector collector2, final java.util.stream.Collector collector3, final java.util.stream.Collector collector4, final java.util.stream.Collector collector5) { final List> collectors = (List) N.asList(collector1, collector2, collector3, collector4, collector5); final Function, Tuple5> func = new Function, Tuple5>() { @Override public Tuple5 apply(List t) { return Tuple5.from(t); } }; return (Collector) collectingAndThen(combine(collectors), func); } /** * * @param collectors * @return * @see Tuple#from(Collection) */ @SuppressWarnings("rawtypes") public static Collector> combine(final Collection> collectors) { 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 = new Supplier>() { @Override public List get() { final List res = new ArrayList<>(len); for (int i = 0; i < len; i++) { res.add(cs[i].supplier().get()); } return res; } }; final BiConsumer, T> accumulator = new BiConsumer, T>() { @Override public void accept(List acct, T e) { for (int i = 0; i < len; i++) { cs[i].accumulator().accept(acct.get(i), e); } } }; final BinaryOperator> combiner = new BinaryOperator>() { @Override public List apply(List t, List u) { for (int i = 0; i < len; i++) { t.set(i, cs[i].combiner().apply(t.get(i), u.get(i))); } return t; } }; 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 : new HashSet<>(common); if (characteristics.contains(Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, combiner, characteristics); } else { final Function, List> finisher = new Function, List>() { @Override public List apply(List t) { for (int i = 0; i < len; i++) { t.set(i, cs[i].finisher().apply(t.get(i))); } return t; } }; return (Collector) new CollectorImpl<>(supplier, accumulator, combiner, finisher, characteristics); } } // public static Collector toDataSet(final String entityName, final Class entityClass, 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(entityName, entityClass, 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 new BinaryOperator() { @Override public M apply(M m1, M m2) { for (Map.Entry e : m2.entrySet()) { final V oldValue = m1.get(e.getKey()); if (oldValue == null && m1.containsKey(e.getKey()) == false) { 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 new BinaryOperator() { @Override public M apply(M m1, M m2) { for (Map.Entry e : m2.entrySet()) { final V oldValue = m1.get(e.getKey()); if (oldValue == null && m1.containsKey(e.getKey()) == false) { 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 new BinaryOperator() { @Override public M apply(M m1, M 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; } }; } @SuppressWarnings("rawtypes") private static final Supplier queueSupplier = new Supplier() { @Override public BlockingQueue get() { return new ArrayBlockingQueue(64); } }; /** * Note: Generally it's much slower than other {@code Collectors}. * * @param streamingCollector * @return * @see Stream#observe(BlockingQueue, Predicate, long) * @see Stream#asyncCall(Try.Function) */ @SuppressWarnings("rawtypes") public static Collector streaming(final Function, R> streamingCollector) { return streaming((Supplier) queueSupplier, streamingCollector); } /** * Note: Generally it's much slower than other {@code Collectors}. * * @param maxWaitIntervalInMillis * @param streamingCollector * @return * @see Stream#observe(BlockingQueue, Predicate, long) * @see Stream#asyncCall(Try.Function) */ @SuppressWarnings("rawtypes") public static Collector streaming(final long maxWaitIntervalInMillis, final Function, R> streamingCollector) { return streaming(maxWaitIntervalInMillis, (Supplier) queueSupplier, streamingCollector); } /** * Note: Generally it's much slower than other {@code Collectors}. * * @param supplier * @param streamingCollector * @return * @see Stream#observe(BlockingQueue, Predicate, long) * @see Stream#asyncCall(Try.Function) */ public static Collector streaming(final Supplier> queueSupplier, final Function, R> streamingCollector) { return streaming(10, queueSupplier, streamingCollector); } /** * Note: Generally it's much slower than other {@code Collectors}. * * @param maxWaitIntervalInMillis * @param supplier * @param streamingCollector * @return * @see Stream#observe(BlockingQueue, Predicate, long) * @see Stream#asyncCall(Try.Function) */ public static Collector streaming(final long maxWaitIntervalInMillis, final Supplier> queueSupplier, final Function, R> streamingCollector) { final Function, ContinuableFuture> streamingCollector2 = new Function, ContinuableFuture>() { @Override public ContinuableFuture apply(Stream t) { return t.asyncCall(streamingCollector); } }; return streaming(queueSupplier, streamingCollector2, maxWaitIntervalInMillis); } /** * Note: Generally it's much slower than other {@code Collectors}. * * @param supplier * @param streamingCollector * @param maxWaitIntervalInMillis * @return * @see Stream#observe(BlockingQueue, Predicate, long) * @see Stream#asyncCall(Try.Function) */ @SuppressWarnings("rawtypes") public static Collector streaming(final Supplier> queueSupplier, final Function, ContinuableFuture> streamingCollector, final long maxWaitIntervalInMillis) { final T NULL = (T) NONE; final Supplier, MutableBoolean, MutableBoolean, Holder>>> supplier = new Supplier, MutableBoolean, MutableBoolean, Holder>>>() { @Override public Tuple4, MutableBoolean, MutableBoolean, Holder>> get() { return Tuple.of((BlockingQueue) queueSupplier.get(), MutableBoolean.of(true), MutableBoolean.of(false), new Holder>()); // _1 = queue, _2 = hasMore, _3 = isComplete, _4=future. } }; final BiConsumer, MutableBoolean, MutableBoolean, Holder>>, T> accumulator = new BiConsumer, MutableBoolean, MutableBoolean, Holder>>, T>() { @Override public void accept(Tuple4, MutableBoolean, MutableBoolean, Holder>> xxx, T t) { if (xxx._4.value() == null) { initStream(xxx, streamingCollector, maxWaitIntervalInMillis, NULL); } t = t == null ? NULL : t; if (xxx._3.isFalse() && xxx._1.offer(t) == false) { try { while (xxx._3.isFalse() && xxx._1.offer(t, maxWaitIntervalInMillis, TimeUnit.MILLISECONDS) == false) { } } catch (InterruptedException e) { throw new RuntimeException(e); } } } }; final BinaryOperator, MutableBoolean, MutableBoolean, Holder>>> combiner = new BinaryOperator, MutableBoolean, MutableBoolean, Holder>>>() { @Override public Tuple4, MutableBoolean, MutableBoolean, Holder>> apply( Tuple4, MutableBoolean, MutableBoolean, Holder>> t, Tuple4, MutableBoolean, MutableBoolean, Holder>> u) { throw new UnsupportedOperationException("Should not happen"); } }; final Function, MutableBoolean, MutableBoolean, Holder>>, R> finisher = new Function, MutableBoolean, MutableBoolean, Holder>>, R>() { @Override public R apply(Tuple4, MutableBoolean, MutableBoolean, Holder>> xxx) { if (xxx._4.value() == null) { initStream(xxx, streamingCollector, maxWaitIntervalInMillis, NULL); } xxx._2.setFalse(); try { return xxx._4.value().get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } }; return new CollectorImpl(supplier, accumulator, combiner, finisher, CH_CONCURRENT_NOID); } private static void initStream(final Tuple4, MutableBoolean, MutableBoolean, Holder>> tp, final Function, ContinuableFuture> streamingCollector, final long maxWaitIntervalInMillis, final T NULL) { synchronized (tp) { if (tp._4.value() == null) { final BooleanSupplier hasMore = new BooleanSupplier() { @Override public boolean getAsBoolean() { return tp._2.value(); } }; tp._4.setValue(streamingCollector.apply(Stream.observe(tp._1, hasMore, maxWaitIntervalInMillis).map(new Function() { @Override public T apply(T t) { return t == NULL ? null : t; } }).onClose(new Runnable() { @Override public void run() { tp._3.setTrue(); while (tp._1.size() > 0) { tp._1.clear(); } } }))); } } } 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) == false) { map.put(key, value); } else { map.put(key, remappingFunction.apply(oldValue, value)); } } public static abstract class MoreCollectors extends Collectors { protected MoreCollectors() { // for extention. } } }









* 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. * *