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

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

There is a newer version: 1.8.1
Show newest version
/*
 * Copyright (C) 2017 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.util.AbstractMap;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.util.Comparators;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.ImmutableMap;
import com.landawn.abacus.util.ListMultimap;
import com.landawn.abacus.util.LongMultiset;
import com.landawn.abacus.util.Multimap;
import com.landawn.abacus.util.Multiset;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Nullable;
import com.landawn.abacus.util.ObjIterator;
import com.landawn.abacus.util.Tuple;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.BiPredicate;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.Predicate;
import com.landawn.abacus.util.function.Supplier;

/**
 * 
 * @since 0.9
 * 
 * @author Haiyang Li
 */
public final class EntryStream implements AutoCloseable {

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

    @SuppressWarnings("rawtypes")
    private static final EntryStream EMPTY = new EntryStream(Stream. empty());

    private final Stream> s;

    EntryStream(final Stream> s) {
        this.s = (Stream>) s;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    static  Function, Stream>> mapFunc() {
        return (Function) mapper_func;
    }

    public static  EntryStream empty() {
        return EMPTY;
    }

    public static  EntryStream of(K k1, V v1) {
        return of(Stream.of(Tuple.of(k1, v1)));
    }

    public static  EntryStream of(K k1, V v1, K k2, V v2) {
        return of(Stream.of(Tuple.of(k1, v1), Tuple.of(k2, v2)));
    }

    public static  EntryStream of(K k1, V v1, K k2, V v2, K k3, V v3) {
        return of(Stream.of(Tuple.of(k1, v1), Tuple.of(k2, v2), Tuple.of(k3, v3)));
    }

    public static  EntryStream of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
        return of(Stream.of(Tuple.of(k1, v1), Tuple.of(k2, v2), Tuple.of(k3, v3), Tuple.of(k4, v4)));
    }

    public static  EntryStream of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
        return of(Stream.of(Tuple.of(k1, v1), Tuple.of(k2, v2), Tuple.of(k3, v3), Tuple.of(k4, v4), Tuple.of(k5, v5)));
    }

    public static  EntryStream of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
        return of(Stream.of(Tuple.of(k1, v1), Tuple.of(k2, v2), Tuple.of(k3, v3), Tuple.of(k4, v4), Tuple.of(k5, v5), Tuple.of(k6, v6)));
    }

    public static  EntryStream of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
        return of(Stream.of(Tuple.of(k1, v1), Tuple.of(k2, v2), Tuple.of(k3, v3), Tuple.of(k4, v4), Tuple.of(k5, v5), Tuple.of(k6, v6), Tuple.of(k7, v7)));
    }

    public static  EntryStream of(final Stream> s) {
        return new EntryStream(s);
    }

    public static  EntryStream of(final Iterator> iterator) {
        return new EntryStream(Stream.of(iterator));
    }

    public static  EntryStream of(final Map map) {
        return new EntryStream(Stream.of(map));
    }

    public static  EntryStream of(final Collection> entries) {
        return new EntryStream(Stream.of(entries));
    }

    //    @SafeVarargs
    //    public static  EntryStream of(final Map.Entry... entries) {
    //        return new EntryStream(Stream.of(entries));
    //    }

    public static  EntryStream of(final Multiset multiset) {
        return multiset == null ? EntryStream. empty() : multiset.entryStream();
    }

    public static  EntryStream of(final LongMultiset multiset) {
        return multiset == null ? EntryStream. empty() : multiset.entryStream();
    }

    public static > EntryStream of(final Multimap mulitmap) {
        return mulitmap == null ? EntryStream. empty() : mulitmap.entryStream();
    }

    public static  EntryStream of(final Collection c, final Function keyExtractor) {
        final Function valueMapper = Fn.identity();

        return Stream.of(c).mapToEntry(keyExtractor, valueMapper);
    }

    public static  EntryStream of(final T[] a, final Function keyExtractor) {
        final Function valueMapper = Fn.identity();

        return Stream.of(a).mapToEntry(keyExtractor, valueMapper);
    }

    @SafeVarargs
    public static  EntryStream concat(final Map... maps) {
        final Function, Stream>> mapper = mapFunc();

        return Stream.of(maps).flatMapToEntry(mapper);
    }

    public static  EntryStream concat(final Collection> maps) {
        final Function, Stream>> mapper = mapFunc();

        return Stream.of(maps).flatMapToEntry(mapper);
    }

    public static  EntryStream zip(final K[] keys, final V[] values) {
        final BiFunction> zipFunction = new BiFunction>() {
            @Override
            public Entry apply(K k, V v) {
                return new AbstractMap.SimpleImmutableEntry<>(k, v);
            }
        };

        final Function, Map.Entry> mapper = Fn.identity();

        return Stream.zip(keys, values, zipFunction).mapToEntry(mapper);
    }

    public static  EntryStream zip(final K[] keys, final V[] values, K valueForNonKey, V valueForNonValue) {
        final BiFunction> zipFunction = new BiFunction>() {
            @Override
            public Entry apply(K k, V v) {
                return new AbstractMap.SimpleImmutableEntry<>(k, v);
            }
        };

        final Function, Map.Entry> mapper = Fn.identity();

        return Stream.zip(keys, values, valueForNonKey, valueForNonValue, zipFunction).mapToEntry(mapper);
    }

    public static  EntryStream zip(final Collection keys, final Collection values) {
        final BiFunction> zipFunction = new BiFunction>() {
            @Override
            public Entry apply(K k, V v) {
                return new AbstractMap.SimpleImmutableEntry<>(k, v);
            }
        };

        final Function, Map.Entry> mapper = Fn.identity();

        return Stream.zip(keys, values, zipFunction).mapToEntry(mapper);
    }

    public static  EntryStream zip(final Collection keys, final Collection values, K valueForNonKey, V valueForNonValue) {
        final BiFunction> zipFunction = new BiFunction>() {
            @Override
            public Entry apply(K k, V v) {
                return new AbstractMap.SimpleImmutableEntry<>(k, v);
            }
        };

        final Function, Map.Entry> mapper = Fn.identity();

        return Stream.zip(keys, values, valueForNonKey, valueForNonValue, zipFunction).mapToEntry(mapper);
    }

    public Stream keys() {
        final Function, K> func = Fn.key();

        return s.map(func);
    }

    public Stream values() {
        final Function, V> func = Fn.value();

        return s.map(func);
    }

    public Stream> entries() {
        return s;
    }

    public EntryStream inversed() {
        final Function, Map.Entry> mapper = new Function, Map.Entry>() {
            @Override
            public Entry apply(Entry e) {
                return new AbstractMap.SimpleImmutableEntry<>(e.getValue(), e.getKey());
            }
        };

        return map(mapper);
    }

    public  EntryStream filter(final Predicate> predicate) {
        return of(s.filter(predicate));
    }

    public  EntryStream filter(final BiPredicate predicate) {
        final Predicate> predicate2 = new Predicate>() {
            @Override
            public boolean test(Entry entry) {
                return predicate.test(entry.getKey(), entry.getValue());
            }
        };

        return of(s.filter(predicate2));
    }

    public  EntryStream filterByKey(final Predicate keyPredicate) {
        final Predicate> predicate = Fn.testByKey(keyPredicate);

        return of(s.filter(predicate));
    }

    public  EntryStream filterByValue(final Predicate valuePredicate) {
        final Predicate> predicate = Fn.testByValue(valuePredicate);

        return of(s.filter(predicate));
    }

    public  EntryStream map(final Function, Map.Entry> mapper) {
        return of(s.map(mapper));
    }

    public  EntryStream map(final BiFunction> mapper) {
        final Function, Map.Entry> mapper2 = new Function, Map.Entry>() {
            @Override
            public Entry apply(Map.Entry entry) {
                return mapper.apply(entry.getKey(), entry.getValue());
            }
        };

        return of(s.map(mapper2));
    }

    public  EntryStream map(final Function keyMapper, final Function valueMapper) {
        final Function, Map.Entry> mapper = new Function, Map.Entry>() {
            @Override
            public Entry apply(Entry t) {
                return new AbstractMap.SimpleImmutableEntry<>(keyMapper.apply(t.getKey()), valueMapper.apply(t.getValue()));
            }
        };

        return map(mapper);
    }

    public  EntryStream mapKey(final Function keyMapper) {
        final Function, Map.Entry> mapper = Fn.mapKey(keyMapper);

        return of(s.map(mapper));
    }

    public  EntryStream mapValue(final Function valueMapper) {
        final Function, Map.Entry> mapper = Fn.mapValue(valueMapper);

        return of(s.map(mapper));
    }

    //    public  EntryStream flatMap(final Function, EntryStream> mapper) {
    //        final Function, Stream>> mapper2 = new Function, Stream>>() {
    //            @Override
    //            public Stream> apply(Entry t) {
    //                return mapper.apply(t).s;
    //            }
    //        };
    //
    //        return flatCollection(mapper2);
    //    }

    public  EntryStream flatMap(final Function, Stream>> mapper) {
        return of(s.flatMap(mapper));
    }

    //    public  EntryStream flatArray(final Function, Map> mapper) {
    //        final Function, Stream>> mapper2 = new Function, Stream>>() {
    //            @Override
    //            public Stream> apply(Entry t) {
    //                return Stream.of(mapper.apply(t));
    //            }
    //        };
    //
    //        return flatMap(mapper2);
    //    }

    public  EntryStream flatMapKey(final Function> keyMapper) {
        final Function, Stream>> mapper2 = new Function, Stream>>() {
            @Override
            public Stream> apply(final Map.Entry e) {
                return keyMapper.apply(e.getKey()).map(new Function>() {
                    @Override
                    public Map.Entry apply(KK kk) {
                        return new AbstractMap.SimpleImmutableEntry<>(kk, e.getValue());
                    }
                });
            }
        };

        return flatMap(mapper2);
    }

    public  EntryStream flatMapValue(final Function> valueMapper) {
        final Function, Stream>> mapper2 = new Function, Stream>>() {
            @Override
            public Stream> apply(final Entry e) {
                return valueMapper.apply(e.getValue()).map(new Function>() {
                    @Override
                    public Map.Entry apply(VV vv) {
                        return new AbstractMap.SimpleImmutableEntry<>(e.getKey(), vv);
                    }
                });
            }
        };

        return flatMap(mapper2);
    }

    /**
     * 
     * @param classifier
     * @return
     * @see Collectors#groupingBy(Function)
     */
    public EntryStream> groupBy() {
        final Function, K> classifier = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return of(s.groupBy(classifier, valueMapper));
    }

    /**
     * 
     * @param classifier
     * @param mapFactory
     * @return
     * @see Collectors#groupingBy(Function, Supplier)
     */
    public EntryStream> groupBy(final Supplier>> mapFactory) {
        final Function, K> classifier = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return of(s.groupBy(classifier, valueMapper, mapFactory));
    }

    public  EntryStream> groupBy(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper) {

        return of(s.groupBy(keyExtractor, valueMapper));
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mapFactory
     * @return
     * @see Collectors#toMultimap(Function, Function, Supplier)
     */
    public  EntryStream> groupBy(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final Supplier>> mapFactory) {

        return of(s.groupBy(keyExtractor, valueMapper, mapFactory));
    }

    /**
     * 
     * @param downstream
     * @return
     * @see Collectors#groupingBy(Function, Collector)
     */
    public  EntryStream groupBy(final Collector, A, D> downstream) {
        final Function, K> classifier = Fn.key();

        return of(s.groupBy(classifier, downstream));
    }

    /**
     * 
     * @param downstream
     * @param mapFactory
     * @return
     * @see Collectors#groupingBy(Function, Collector)
     */
    public  EntryStream groupBy(final Collector, A, D> downstream, final Supplier> mapFactory) {
        final Function, K> classifier = Fn.key();

        return of(s.groupBy(classifier, downstream, mapFactory));
    }

    /**
     * 
     * @param classifier
     * @param downstream
     * @param mapFactory
     * @return
     * @see Collectors#groupingBy(Function, Collector, Supplier)
     */
    public  EntryStream groupBy(final Function, ? extends KK> classifier,
            final Collector, A, D> downstream) {

        return of(s.groupBy(classifier, downstream));
    }

    /**
     * 
     * @param classifier
     * @param downstream
     * @return
     * @see Collectors#groupingBy(Function, Collector)
     */
    public  EntryStream groupBy(final Function, ? extends KK> classifier,
            final Collector, A, D> downstream, final Supplier> mapFactory) {

        return of(s.groupBy(classifier, downstream, mapFactory));
    }

    /**
     * 
     * @param mergeFunction
     * @return
     */
    public EntryStream groupBy(final BinaryOperator mergeFunction) {
        final Function, K> classifier = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return of(s.groupBy(classifier, valueMapper, mergeFunction));
    }

    /**
     * 
     * @param mergeFunction
     * @param mapFactory
     * @return
     */
    public EntryStream groupBy(final BinaryOperator mergeFunction, final Supplier> mapFactory) {
        final Function, K> classifier = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return of(s.groupBy(classifier, valueMapper, mergeFunction, mapFactory));
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mergeFunction
     * @return
     * @see Collectors#groupBy(Function, Function, BinaryOperator)
     */
    public  EntryStream groupBy(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final BinaryOperator mergeFunction) {

        return of(s.groupBy(keyExtractor, valueMapper, mergeFunction));
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mergeFunction
     * @param mapFactory
     * @return
     * @see Collectors#groupBy(Function, Function, BinaryOperator, Supplier)
     */
    public  EntryStream groupBy(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final BinaryOperator mergeFunction, final Supplier> mapFactory) {

        return of(s.groupBy(keyExtractor, valueMapper, mergeFunction, mapFactory));
    }

    public EntryStream sorted(final Comparator> comparator) {
        return of(s.sorted(comparator));
    }

    public EntryStream sortedByKey(final Comparator keyComparator) {
        final Comparator> comparator = Comparators.comparingByKey(keyComparator);

        return of(s.sorted(comparator));
    }

    public EntryStream sortedByValue(final Comparator valueComparator) {
        final Comparator> comparator = Comparators.comparingByValue(valueComparator);

        return of(s.sorted(comparator));
    }

    @SuppressWarnings("rawtypes")
    public EntryStream sortedBy(Function, ? extends Comparable> keyExtractor) {
        return of(s.sortedBy(keyExtractor));
    }

    public EntryStream distinct() {
        return of(s.distinct());
    }

    public EntryStream distinctByKey() {
        final Function, K> keyExtractor = Fn.key();

        return of(s.distinctBy(keyExtractor));
    }

    public EntryStream distinctByValue() {
        final Function, V> keyExtractor = Fn.value();

        return of(s.distinctBy(keyExtractor));
    }

    public EntryStream distinctBy(final Function, ?> keyExtractor) {
        return of(s.distinctBy(keyExtractor));
    }

    public EntryStream reversed() {
        return of(s.reversed());
    }

    public EntryStream shuffled() {
        return of(s.shuffled());
    }

    public EntryStream shuffled(final Random rnd) {
        return of(s.shuffled(rnd));
    }

    public EntryStream rotated(final int distance) {
        return of(s.rotated(distance));
    }

    public EntryStream skip(long n) {
        return of(s.skip(n));
    }

    public EntryStream limit(long n) {
        return of(s.limit(n));
    }

    public EntryStream peek(final Consumer> action) {
        return of(s.peek(action));
    }

    public EntryStream peek(final BiConsumer action) {
        final Consumer> action2 = new Consumer>() {
            @Override
            public void accept(Entry entry) {
                action.accept(entry.getKey(), entry.getValue());
            }
        };

        return of(s.peek(action2));
    }

    public void forEach(final Consumer> action) {
        s.forEach(action);
    }

    public void forEach(final BiConsumer action) {
        final Consumer> action2 = new Consumer>() {
            @Override
            public void accept(Entry entry) {
                action.accept(entry.getKey(), entry.getValue());
            }
        };

        s.forEach(action2);
    }

    public long count() {
        return s.count();
    }

    public ObjIterator> iterator() {
        return s.iterator();
    }

    /**
     * 
     * @return
     */
    public ImmutableMap toImmutableMap() {
        return ImmutableMap.of(toMap());
    }

    /**
     * 
     * @return
     */
    public ImmutableMap toImmutableMap(final BinaryOperator mergeFunction) {
        return ImmutableMap.of(toMap(mergeFunction));
    }

    /**
     * 
     * @return
     */
    public Map toMap() {
        final Collector, ?, Map> collector = Collectors.toMap();

        return s.collect(collector);
    }

    /**
     * 
     * @param mergeFunction
     * @return
     */
    public Map toMap(final BinaryOperator mergeFunction) {
        final Collector, ?, Map> collector = Collectors.toMap(mergeFunction);

        return s.collect(collector);
    }

    /**
     * 
     * @param mapFactory
     * @return
     */
    public > M toMap(final Supplier mapFactory) {
        final Collector, ?, M> collector = Collectors.toMap(mapFactory);

        return s.collect(collector);
    }

    /**
     * 
     * @param mergeFunction
     * @param mapFactory
     * @return
     */
    public > M toMap(final BinaryOperator mergeFunction, final Supplier mapFactory) {
        final Function, K> keyExtractor = Fn.key();
        final Function, V> valueMapper = Fn.value();

        final Collector, ?, M> collector = Collectors.toMap(keyExtractor, valueMapper, mergeFunction, mapFactory);

        return s.collect(collector);
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @return
     * @see Collectors#toMap(Function, Function)
     */
    public  Map toMap(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper) {
        return s.toMap(keyExtractor, valueMapper);
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mapFactory
     * @return
     * @see Collectors#toMap(Function, Function, Supplier)
     */
    public > M toMap(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final Supplier mapFactory) {
        return s.toMap(keyExtractor, valueMapper, mapFactory);
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mergeFunction
     * @return
     * @see Collectors#toMap(Function, Function, BinaryOperator)
     */
    public  Map toMap(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final BinaryOperator mergeFunction) {
        return s.toMap(keyExtractor, valueMapper, mergeFunction);
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mergeFunction
     * @param mapFactory
     * @return
     * @see Collectors#toMap(Function, Function, BinaryOperator, Supplier)
     */
    public > M toMap(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final BinaryOperator mergeFunction, final Supplier mapFactory) {
        return s.toMap(keyExtractor, valueMapper, mergeFunction, mapFactory);
    }

    /**
     * 
     * @param downstream
     * @return
     * @see Collectors#groupingBy(Function, Collector)
     */
    public  Map toMap(final Collector, A, D> downstream) {
        final Function, K> keyExtractor = Fn.key();
        return s.toMap(keyExtractor, downstream);
    }

    /**
     * 
     * @param downstream
     * @param mapFactory
     * @return
     * @see Collectors#groupingBy(Function, Collector)
     */
    public > M toMap(final Collector, A, D> downstream, final Supplier mapFactory) {
        final Function, K> keyExtractor = Fn.key();

        return s.toMap(keyExtractor, downstream, mapFactory);
    }

    /**
     * 
     * @param classifier
     * @param downstream
     * @param mapFactory
     * @return
     * @see Collectors#groupingBy(Function, Collector, Supplier)
     */
    public  Map toMap(final Function, ? extends KK> classifier,
            final Collector, A, D> downstream) {
        return s.toMap(classifier, downstream);
    }

    /**
     * 
     * @param classifier
     * @param downstream
     * @return
     * @see Collectors#groupingBy(Function, Collector)
     */
    public > M toMap(final Function, ? extends KK> classifier,
            final Collector, A, D> downstream, final Supplier mapFactory) {
        return s.toMap(classifier, downstream, mapFactory);
    }

    public  R toMapAndThen(Function, R> func) {
        return func.apply(toMap());
    }

    /**
     * 
     * @param classifier
     * @return
     * @see Collectors#groupingBy(Function)
     */
    public Map> groupTo() {
        final Function, K> keyExtractor = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return s.groupTo(keyExtractor, valueMapper);
    }

    /**
     * 
     * @param classifier
     * @param mapFactory
     * @return
     * @see Collectors#groupingBy(Function, Supplier)
     */
    public >> M groupTo(final Supplier mapFactory) {
        final Function, K> keyExtractor = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return s.groupTo(keyExtractor, valueMapper, mapFactory);
    }

    public  Map> groupTo(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper) {
        return s.groupTo(keyExtractor, valueMapper);
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mapFactory
     * @return
     * @see Collectors#toMultimap(Function, Function, Supplier)
     */
    public >> M groupTo(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final Supplier mapFactory) {

        return s.groupTo(keyExtractor, valueMapper, mapFactory);
    }

    public  R groupToAndThen(Function>, R> func) {
        return func.apply(groupTo());
    }

    /**
     * 
     * @param keyExtractor
     * @return
     * @see Collectors#toMultimap(Function, Function)
     */
    public ListMultimap toMultimap() {
        final Function, K> keyExtractor = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return s.toMultimap(keyExtractor, valueMapper);
    }

    /**
     * 
     * @param keyExtractor
     * @param mapFactory
     * @return
     * @see Collectors#toMultimap(Function, Function, Supplier)
     */
    public , M extends Multimap> M toMultimap(final Supplier mapFactory) {
        final Function, K> keyExtractor = Fn.key();
        final Function, V> valueMapper = Fn.value();

        return s.toMultimap(keyExtractor, valueMapper, mapFactory);
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @return
     * @see Collectors#toMultimap(Function, Function)
     */
    public  ListMultimap toMultimap(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper) {
        return s.toMultimap(keyExtractor, valueMapper);
    }

    /**
     * 
     * @param keyExtractor
     * @param valueMapper
     * @param mapFactory
     * @return
     * @see Collectors#toMultimap(Function, Function, Supplier)
     */
    public , M extends Multimap> M toMultimap(final Function, ? extends KK> keyExtractor,
            final Function, ? extends VV> valueMapper, final Supplier mapFactory) {
        return s.toMultimap(keyExtractor, valueMapper, mapFactory);
    }

    /**
     * 
     * @param collapsible
     * @param mergeFunction
     * @return
     * @see Stream#collapse(BiPredicate, BiFunction)
     */
    public Stream> collapseByKey(final BiPredicate collapsible,
            final BiFunction, ? super Entry, Entry> mergeFunction) {

        final BiPredicate, ? super Entry> collapsible2 = new BiPredicate, Entry>() {
            @Override
            public boolean test(Entry t, Entry u) {
                return collapsible.test(t.getKey(), u.getKey());
            }
        };

        return s.collapse(collapsible2, mergeFunction);
    }

    /**
     * 
     * @param collapsible
     * @return
     * @see Stream#collapse(BiPredicate, Collector)
     */
    public Stream> collapseByKey(final BiPredicate collapsible) {
        final BiPredicate, ? super Entry> collapsible2 = new BiPredicate, Entry>() {
            @Override
            public boolean test(Entry t, Entry u) {
                return collapsible.test(t.getKey(), u.getKey());
            }
        };

        final Function, V> mapper = Fn.value();
        final Collector> collector = Collectors.toList();

        return s.collapse(collapsible2, Collectors.mapping(mapper, collector));
    }

    /**
     * Merge series of adjacent elements which satisfy the given predicate using
     * the merger function and return a new stream.
     * 
     * 
* This method only run sequentially, even in parallel stream. * * @param collapsible * @param collector * @return */ public Stream collapseByKey(final BiPredicate collapsible, final Collector, A, R> collector) { final BiPredicate, ? super Entry> collapsible2 = new BiPredicate, Entry>() { @Override public boolean test(Entry t, Entry u) { return collapsible.test(t.getKey(), u.getKey()); } }; return s.collapse(collapsible2, collector); } public Map.Entry reduce(final Map.Entry identity, final BinaryOperator> accumulator) { return s.reduce(identity, accumulator); } public Nullable> reduce(final BinaryOperator> accumulator) { return s.reduce(accumulator); } public U reduce(final U identity, final BiFunction, U> accumulator, final BinaryOperator combiner) { return s.reduce(identity, accumulator, combiner); } public U reduce(final U identity, final BiFunction, U> accumulator) { return s.reduce(identity, accumulator); } public R collect(final Supplier supplier, final BiConsumer> accumulator, final BiConsumer combiner) { return s.collect(supplier, accumulator, combiner); } public R collect(final Supplier supplier, final BiConsumer> accumulator) { return s.collect(supplier, accumulator); } public R collect(final Collector, A, R> collector) { return s.collect(collector); } public RR collectAndThen(final Collector, A, R> downstream, final Function finisher) { return s.collectAndThen(downstream, finisher); } public EntryStream chain(Function>, ? extends Stream>> transfer) { return of(transfer.apply(s)); } public R __(Function, R> transfer) { return transfer.apply(this); } public EntryStream sequential() { return s.isParallel() ? of(s.sequential()) : this; } public EntryStream parallel() { return of(s.parallel()); } public EntryStream parallel(int threadNum) { return of(s.parallel(threadNum)); } public boolean isParallel() { return s.isParallel(); } /** * To reduce the memory footprint, Only one instance of Map.Entry is created, * and the same entry instance is returned and set with different keys/values during iteration of the returned stream. * The elements only can be retrieved one by one, can't be modified or saved. * The returned Stream doesn't support the operations which require two or more elements at the same time: (e.g. sort/distinct/pairMap/slidingMap/sliding/split/toList/toSet/...). * , and can't be parallel stream. * Operations: filter/map/toMap/groupBy/groupTo/... are supported. * *
* ER = Entry Reusable * * * @param keyMapper * @param valueMapper * @return */ @Beta public EntryStream mapER(final Function keyMapper, final Function valueMapper) { N.checkState(s.isParallel() == false, "mapER can't be applied to parallel stream"); final Function, Map.Entry> mapper = new Function, Map.Entry>() { private final ReusableEntry entry = new ReusableEntry<>(); @Override public Entry apply(Entry t) { entry.set(keyMapper.apply(t.getKey()), valueMapper.apply(t.getValue())); return entry; } }; return map(mapper); } /** * * @param keyMapper * @return * @see #mapER(Function, Function) */ @Beta public EntryStream flatMapKeyER(final Function> keyMapper) { N.checkState(s.isParallel() == false, "flatMapKeyER can't be applied to parallel stream"); final Function, Stream>> mapper2 = new Function, Stream>>() { @Override public Stream> apply(final Map.Entry e) { return keyMapper.apply(e.getKey()).map(new Function>() { private final ReusableEntry entry = new ReusableEntry<>(); @Override public Map.Entry apply(KK kk) { entry.set(kk, e.getValue()); return entry; } }); } }; return flatMap(mapper2); } /** * * @param valueMapper * @return * @see #mapER(Function, Function) */ @Beta public EntryStream flatMapValueER(final Function> valueMapper) { N.checkState(s.isParallel() == false, "flatMapValueER can't be applied to parallel stream"); final Function, Stream>> mapper2 = new Function, Stream>>() { @Override public Stream> apply(final Entry e) { return valueMapper.apply(e.getValue()).map(new Function>() { private final ReusableEntry entry = new ReusableEntry<>(); @Override public Map.Entry apply(VV vv) { entry.set(e.getKey(), vv); return entry; } }); } }; return flatMap(mapper2); } /** * @return * @see #mapER(Function, Function) */ @Beta public EntryStream inversedER() { N.checkState(s.isParallel() == false, "inversedER can't be applied to parallel stream"); final Function, Map.Entry> mapper = new Function, Map.Entry>() { private final ReusableEntry entry = new ReusableEntry<>(); @Override public Entry apply(Entry e) { entry.set(e.getValue(), e.getKey()); return entry; } }; return map(mapper); } public EntryStream onClose(Runnable closeHandler) { return of(s.onClose(closeHandler)); } @Override public void close() { s.close(); } static class ReusableEntry implements Map.Entry { private K key = null; private V value = null; private boolean flag = false; //check if it's used/read. @Override public K getKey() { flag = false; return key; } @Override public V getValue() { flag = false; return value; } @Override public V setValue(V value) { throw new UnsupportedOperationException(); } public void set(K key, V value) { if (flag) { throw new IllegalStateException(); } this.key = key; this.value = value; this.flag = true; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof ReusableEntry) { final ReusableEntry other = (ReusableEntry) obj; return N.equals(key, other.key) && N.equals(value, other.value); } return false; } @Override public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } @Override public String toString() { flag = false; return key + "=" + value; } } }