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.10.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.SimpleImmutableEntry;
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 java.util.Set;

import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.util.BiIterator;
import com.landawn.abacus.util.Comparators;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.ImmutableMap;
import com.landawn.abacus.util.Joiner;
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.ObjIterator;
import com.landawn.abacus.util.Optional;
import com.landawn.abacus.util.Pair;
import com.landawn.abacus.util.Try;
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.BooleanSupplier;
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;
import com.landawn.abacus.util.function.ToDoubleFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.ToLongFunction;
import com.landawn.abacus.util.stream.BaseStream.Splitor;

/**
 * 
 * @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 Map m;
    private final Stream> s;

    EntryStream(final Stream> s) {
        this(null, s);
    }

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

    public Stream keys() {
        if (m != null) {
            return Stream.of(m.keySet());
        }

        final Function, K> func = Fn.key();

        return s.map(func);
    }

    public Stream values() {
        if (m != null) {
            return Stream.of(m.values());
        }

        final Function, V> func = Fn.value();

        return s.map(func);
    }

    public Stream> entries() {
        return s;
    }

    @ParallelSupported
    public EntryStream inversed() {
        final Function, Map.Entry> mapper = Fn.inverse();

        return map(mapper);
    }

    /**
     * Returns a stream consisting of the elements of this stream which keys are
     * instances of given class.
     *
     * 

* This is an intermediate * operation. * * @param a type of keys to select. * @param clazz a class to filter the keys. * @return the new stream */ @SuppressWarnings({ "unchecked" }) @SequentialOnly public EntryStream selectByKey(Class clazz) { if (isParallel()) { return (EntryStream) sequential().filterByKey(Fn.instanceOf(clazz)).parallel(maxThreadNum(), splitor()); } else { return (EntryStream) filterByKey(Fn.instanceOf(clazz)); } } /** * Returns a stream consisting of the elements of this stream which values * are instances of given class. * *

* This is an intermediate * operation. * * @param a type of values to select. * @param clazz a class to filter the values. * @return the new stream */ @SuppressWarnings({ "unchecked" }) @SequentialOnly public EntryStream selectByValue(Class clazz) { if (isParallel()) { return (EntryStream) sequential().filterByValue(Fn.instanceOf(clazz)).parallel(maxThreadNum(), splitor()); } else { return (EntryStream) filterByValue(Fn.instanceOf(clazz)); } } @ParallelSupported public EntryStream filter(final Predicate> predicate) { return of(s.filter(predicate)); } @ParallelSupported 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)); } @ParallelSupported public EntryStream filterByKey(final Predicate keyPredicate) { final Predicate> predicate = Fn.testByKey(keyPredicate); return of(s.filter(predicate)); } @ParallelSupported public EntryStream filterByValue(final Predicate valuePredicate) { final Predicate> predicate = Fn.testByValue(valuePredicate); return of(s.filter(predicate)); } @ParallelSupported public EntryStream removeIf(final Predicate> predicate) { return of(s.removeIf(predicate)); } @ParallelSupported public EntryStream removeIf(final BiPredicate predicate) { final Predicate> predicate2 = new Predicate>() { @Override public boolean test(Entry entry) { return predicate.test(entry.getKey(), entry.getValue()); } }; return of(s.removeIf(predicate2)); } @ParallelSupported public EntryStream takeWhile(final Predicate> predicate) { return of(s.takeWhile(predicate)); } @ParallelSupported public EntryStream takeWhile(final BiPredicate predicate) { final Predicate> predicate2 = new Predicate>() { @Override public boolean test(Entry entry) { return predicate.test(entry.getKey(), entry.getValue()); } }; return of(s.takeWhile(predicate2)); } @ParallelSupported public EntryStream dropWhile(final Predicate> predicate) { return of(s.dropWhile(predicate)); } @ParallelSupported public EntryStream dropWhile(final BiPredicate predicate) { final Predicate> predicate2 = new Predicate>() { @Override public boolean test(Entry entry) { return predicate.test(entry.getKey(), entry.getValue()); } }; return of(s.dropWhile(predicate2)); } @ParallelSupported public EntryStream map(final Function, Map.Entry> mapper) { return s.mapToEntry(mapper); } @ParallelSupported public EntryStream map(final Function, KK> keyMapper, final Function, VV> valueMapper) { return s.mapToEntry(keyMapper, valueMapper); } @ParallelSupported 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 map(mapper2); } @ParallelSupported public EntryStream map(final BiFunction keyMapper, final BiFunction valueMapper) { final Function, Map.Entry> mapper = new Function, Map.Entry>() { @Override public Entry apply(Entry t) { return new SimpleImmutableEntry<>(keyMapper.apply(t.getKey(), t.getValue()), valueMapper.apply(t.getKey(), t.getValue())); } }; return map(mapper); } @ParallelSupported public EntryStream mapKey(final Function keyMapper) { final Function, Map.Entry> mapper = Fn.mapKey(keyMapper); return map(mapper); } @ParallelSupported public EntryStream mapValue(final Function valueMapper) { final Function, Map.Entry> mapper = Fn.mapValue(valueMapper); return 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 flattMap(mapper2); // } @ParallelSupported public EntryStream flatMap(final Function, ? extends Stream>> mapper) { return s.flatMapToEntry(mapper); } @ParallelSupported public EntryStream flattMap(final Function, ? extends Map> mapper) { return s.flattMapToEntry(mapper); } @ParallelSupported public EntryStream flatMapp(final Function, ? extends EntryStream> mapper) { return s.flatMappToEntry(mapper); } @ParallelSupported 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 SimpleImmutableEntry<>(kk, e.getValue()); } }); } }; return flatMap(mapper2); } @ParallelSupported public EntryStream flattMapKey(final Function> keyMapper) { final Function, Stream>> mapper2 = new Function, Stream>>() { @Override public Stream> apply(final Map.Entry e) { return Stream.of(keyMapper.apply(e.getKey())).map(new Function>() { @Override public Map.Entry apply(KK kk) { return new SimpleImmutableEntry<>(kk, e.getValue()); } }); } }; return flatMap(mapper2); } @ParallelSupported 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 SimpleImmutableEntry<>(e.getKey(), vv); } }); } }; return flatMap(mapper2); } @ParallelSupported public EntryStream flattMapValue(final Function> valueMapper) { final Function, Stream>> mapper2 = new Function, Stream>>() { @Override public Stream> apply(final Entry e) { return Stream.of(valueMapper.apply(e.getValue())).map(new Function>() { @Override public Map.Entry apply(VV vv) { return new SimpleImmutableEntry<>(e.getKey(), vv); } }); } }; return flatMap(mapper2); } /** * * @param classifier * @return * @see Collectors#groupingBy(Function) */ @SequentialOnly public EntryStream> groupBy() { final Function, K> classifier = Fn.key(); final Function, V> valueMapper = Fn.value(); if (isParallel()) { return of(s.sequential().groupBy(classifier, valueMapper).parallel(s.maxThreadNum(), s.splitor())); } else { return of(s.groupBy(classifier, valueMapper)); } } /** * * @param classifier * @param mapFactory * @return * @see Collectors#groupingBy(Function, Supplier) */ @SequentialOnly public EntryStream> groupBy(final Supplier>> mapFactory) { final Function, K> classifier = Fn.key(); final Function, V> valueMapper = Fn.value(); if (isParallel()) { return of(s.sequential().groupBy(classifier, valueMapper, mapFactory).parallel(s.maxThreadNum(), s.splitor())); } else { return of(s.groupBy(classifier, valueMapper, mapFactory)); } } @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported 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 */ @SequentialOnly public EntryStream groupBy(final BinaryOperator mergeFunction) { final Function, K> classifier = Fn.key(); final Function, V> valueMapper = Fn.value(); if (isParallel()) { return of(s.sequential().groupBy(classifier, valueMapper, mergeFunction).parallel(s.maxThreadNum(), s.splitor())); } else { return of(s.groupBy(classifier, valueMapper, mergeFunction)); } } /** * * @param mergeFunction * @param mapFactory * @return */ @SequentialOnly public EntryStream groupBy(final BinaryOperator mergeFunction, final Supplier> mapFactory) { final Function, K> classifier = Fn.key(); final Function, V> valueMapper = Fn.value(); if (isParallel()) { return of(s.sequential().groupBy(classifier, valueMapper, mergeFunction, mapFactory).parallel(s.maxThreadNum(), s.splitor())); } else { return of(s.groupBy(classifier, valueMapper, mergeFunction, mapFactory)); } } /** * * @param keyExtractor * @param valueMapper * @param mergeFunction * @return * @see Collectors#groupBy(Function, Function, BinaryOperator) */ @ParallelSupported 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) */ @ParallelSupported 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)); } @ParallelSupported public EntryStream sorted(final Comparator> comparator) { return of(s.sorted(comparator)); } @ParallelSupported public EntryStream sortedByKey(final Comparator keyComparator) { final Comparator> comparator = Comparators.comparingByKey(keyComparator); return of(s.sorted(comparator)); } @ParallelSupported public EntryStream sortedByValue(final Comparator valueComparator) { final Comparator> comparator = Comparators.comparingByValue(valueComparator); return of(s.sorted(comparator)); } @SuppressWarnings("rawtypes") @ParallelSupported public EntryStream sortedBy(Function, ? extends Comparable> keyExtractor) { return of(s.sortedBy(keyExtractor)); } /** * * @param keyExtractor * @return */ @ParallelSupported public EntryStream sortedByInt(final ToIntFunction> keyExtractor) { final Comparator> comparator = Comparators.comparingInt(keyExtractor); return sorted(comparator); } /** * * @param keyExtractor * @return */ @ParallelSupported public EntryStream sortedByLong(final ToLongFunction> keyExtractor) { final Comparator> comparator = Comparators.comparingLong(keyExtractor); return sorted(comparator); } /** * * @param keyExtractor * @return */ @ParallelSupported public EntryStream sortedByDouble(final ToDoubleFunction> keyExtractor) { final Comparator> comparator = Comparators.comparingDouble(keyExtractor); return sorted(comparator); } @SequentialOnly public EntryStream distinct() { return of(s.distinct()); } @SequentialOnly public EntryStream distinctByKey() { final Function, K> keyExtractor = Fn.key(); if (isParallel()) { return of(s.sequential().distinctBy(keyExtractor).parallel(s.maxThreadNum(), s.splitor())); } else { return of(s.distinctBy(keyExtractor)); } } @SequentialOnly public EntryStream distinctByValue() { final Function, V> keyExtractor = Fn.value(); if (isParallel()) { return of(s.sequential().distinctBy(keyExtractor).parallel(s.maxThreadNum(), s.splitor())); } else { return of(s.distinctBy(keyExtractor)); } } @ParallelSupported public EntryStream distinctBy(final Function, ?> keyExtractor) { return of(s.distinctBy(keyExtractor)); } @ParallelSupported public EntryStream distinct(final Predicate occurrencesFilter) { return of(s.distinct(occurrencesFilter)); } @ParallelSupported public EntryStream distinctBy(final Function, ?> keyExtractor, final Predicate occurrencesFilter) { return of(s.distinctBy(keyExtractor, occurrencesFilter)); } @SequentialOnly public EntryStream reversed() { return of(s.reversed()); } @SequentialOnly public EntryStream shuffled() { return of(s.shuffled()); } @SequentialOnly public EntryStream shuffled(final Random rnd) { return of(s.shuffled(rnd)); } @SequentialOnly public EntryStream rotated(final int distance) { return of(s.rotated(distance)); } @SuppressWarnings("rawtypes") @SequentialOnly public EntryStream append(Map map) { if (N.isNullOrEmpty(map)) { return this; } final Set> set = (Set) map.entrySet(); return of(s.append(set)); } @SuppressWarnings("rawtypes") @SequentialOnly public EntryStream prepend(Map map) { if (N.isNullOrEmpty(map)) { return this; } final Set> set = (Set) map.entrySet(); return of(s.prepend(set)); } @SequentialOnly public EntryStream skip(long n) { return of(s.skip(n)); } @SequentialOnly public EntryStream limit(long n) { return of(s.limit(n)); } @ParallelSupported public EntryStream peek(final Consumer> action) { return of(s.peek(action)); } @ParallelSupported 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)); } @ParallelSupported public void forEach(final Try.Consumer, E> action) throws E { s.forEach(action); } @ParallelSupported public void forEach(final Try.BiConsumer action) throws E { final Try.Consumer, E> action2 = new Try.Consumer, E>() { @Override public void accept(Entry entry) throws E { action.accept(entry.getKey(), entry.getValue()); } }; s.forEach(action2); } @ParallelSupported public Optional> min(Comparator> comparator) { return s.min(comparator); } @ParallelSupported public Optional> minByKey(Comparator keyComparator) { return s.min(Comparators.comparingBy(Fn. key(), keyComparator)); } @ParallelSupported public Optional> minByValue(Comparator valueComparator) { return s.min(Comparators.comparingBy(Fn. value(), valueComparator)); } @ParallelSupported @SuppressWarnings("rawtypes") public Optional> minBy(final Function, ? extends Comparable> keyExtractor) { return s.minBy(keyExtractor); } @ParallelSupported public Optional> max(Comparator> comparator) { return s.max(comparator); } @ParallelSupported public Optional> maxByKey(Comparator keyComparator) { return s.max(Comparators.comparingBy(Fn. key(), keyComparator)); } @ParallelSupported public Optional> maxByValue(Comparator valueComparator) { return s.max(Comparators.comparingBy(Fn. value(), valueComparator)); } @ParallelSupported @SuppressWarnings("rawtypes") public Optional> maxBy(final Function, ? extends Comparable> keyExtractor) { return s.maxBy(keyExtractor); } @ParallelSupported public boolean anyMatch(final Try.Predicate, E> predicate) throws E { return s.anyMatch(predicate); } @ParallelSupported public boolean anyMatch(final Try.BiPredicate predicate) throws E { final Try.Predicate, E> predicate2 = new Try.Predicate, E>() { @Override public boolean test(Entry entry) throws E { return predicate.test(entry.getKey(), entry.getValue()); } }; return s.anyMatch(predicate2); } @ParallelSupported public boolean allMatch(final Try.Predicate, E> predicate) throws E { return s.allMatch(predicate); } @ParallelSupported public boolean allMatch(final Try.BiPredicate predicate) throws E { final Try.Predicate, E> predicate2 = new Try.Predicate, E>() { @Override public boolean test(Entry entry) throws E { return predicate.test(entry.getKey(), entry.getValue()); } }; return s.allMatch(predicate2); } @ParallelSupported public boolean noneMatch(final Try.Predicate, E> predicate) throws E { return s.noneMatch(predicate); } @ParallelSupported public boolean noneMatch(final Try.BiPredicate predicate) throws E { final Try.Predicate, E> predicate2 = new Try.Predicate, E>() { @Override public boolean test(Entry entry) throws E { return predicate.test(entry.getKey(), entry.getValue()); } }; return s.noneMatch(predicate2); } @ParallelSupported public Optional> findFirst(final Try.Predicate, E> predicate) throws E { return s.findFirst(predicate); } @ParallelSupported public Optional> findFirst(final Try.BiPredicate predicate) throws E { final Try.Predicate, E> predicate2 = new Try.Predicate, E>() { @Override public boolean test(Entry entry) throws E { return predicate.test(entry.getKey(), entry.getValue()); } }; return s.findFirst(predicate2); } @ParallelSupported public Optional> findAny(final Try.Predicate, E> predicate) throws E { return s.findAny(predicate); } @ParallelSupported public Optional> findAny(final Try.BiPredicate predicate) throws E { final Try.Predicate, E> predicate2 = new Try.Predicate, E>() { @Override public boolean test(Entry entry) throws E { return predicate.test(entry.getKey(), entry.getValue()); } }; return s.findAny(predicate2); } @SequentialOnly public Optional> first() { return s.first(); } @SequentialOnly public Optional> last() { return s.last(); } @SequentialOnly public long count() { return s.count(); } @SequentialOnly public ObjIterator> iterator() { return s.iterator(); } @SequentialOnly public BiIterator biIterator() { final ObjIterator> iter = iterator(); final BooleanSupplier hasNext = new BooleanSupplier() { @Override public boolean getAsBoolean() { return iter.hasNext(); } }; final Consumer> output = new Consumer>() { private Entry entry = null; @Override public void accept(Pair t) { entry = iter.next(); t.set(entry.getKey(), entry.getValue()); } }; return BiIterator.generate(hasNext, output); } /** * * @return */ @ParallelSupported public ImmutableMap toImmutableMap() { return ImmutableMap.of(toMap()); } /** * * @return */ @ParallelSupported public ImmutableMap toImmutableMap(final BinaryOperator mergeFunction) { return ImmutableMap.of(toMap(mergeFunction)); } /** * * @return */ @SequentialOnly public Map toMap() { if (isParallel()) { return s.sequential().toMap(Fn. key(), Fn. value()); } else { return s.toMap(Fn. key(), Fn. value()); } } /** * * @param mergeFunction * @return */ @SequentialOnly public Map toMap(final BinaryOperator mergeFunction) { if (isParallel()) { return s.sequential().toMap(Fn. key(), Fn. value(), mergeFunction); } else { return s.toMap(Fn. key(), Fn. value(), mergeFunction); } } /** * * @param mapFactory * @return */ @SequentialOnly public > M toMap(final Supplier mapFactory) { if (isParallel()) { return s.sequential().toMap(Fn. key(), Fn. value(), mapFactory); } else { return s.toMap(Fn. key(), Fn. value(), mapFactory); } } /** * * @param mergeFunction * @param mapFactory * @return */ @SequentialOnly public > M toMap(final BinaryOperator mergeFunction, final Supplier mapFactory) { if (isParallel()) { return s.sequential().toMap(Fn. key(), Fn. value(), mergeFunction, mapFactory); } else { return s.toMap(Fn. key(), Fn. value(), mergeFunction, mapFactory); } } /** * * @param keyExtractor * @param valueMapper * @return * @see Collectors#toMap(Function, Function) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @ParallelSupported public > M toMap(final Collector, A, D> downstream, final Supplier mapFactory) { return s.toMap(Fn. key(), downstream, mapFactory); } /** * * @param classifier * @param downstream * @param mapFactory * @return * @see Collectors#groupingBy(Function, Collector, Supplier) */ @ParallelSupported 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) */ @ParallelSupported public > M toMap(final Function, ? extends KK> classifier, final Collector, A, D> downstream, final Supplier mapFactory) { return s.toMap(classifier, downstream, mapFactory); } @SequentialOnly public R toMapAndThen(Function, R> func) { return func.apply(toMap()); } /** * * @param classifier * @return * @see Collectors#groupingBy(Function) */ @SequentialOnly public Map> groupTo() { if (isParallel()) { return s.sequential().groupTo(Fn. key(), Fn. value()); } else { return s.groupTo(Fn. key(), Fn. value()); } } /** * * @param classifier * @param mapFactory * @return * @see Collectors#groupingBy(Function, Supplier) */ @SequentialOnly public >> M groupTo(final Supplier mapFactory) { if (isParallel()) { return s.sequential().groupTo(Fn. key(), Fn. value(), mapFactory); } else { return s.groupTo(Fn. key(), Fn. value(), mapFactory); } } @ParallelSupported 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) */ @ParallelSupported public >> M groupTo(final Function, ? extends KK> keyExtractor, final Function, ? extends VV> valueMapper, final Supplier mapFactory) { return s.groupTo(keyExtractor, valueMapper, mapFactory); } @SequentialOnly public R groupToAndThen(Function>, R> func) { return func.apply(groupTo()); } /** * * @param keyExtractor * @return * @see Collectors#toMultimap(Function, Function) */ @SequentialOnly public ListMultimap toMultimap() { if (isParallel()) { return s.sequential().toMultimap(Fn. key(), Fn. value()); } else { return s.toMultimap(Fn. key(), Fn. value()); } } /** * * @param keyExtractor * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ @SequentialOnly public , M extends Multimap> M toMultimap(final Supplier mapFactory) { if (isParallel()) { return s.sequential().toMultimap(Fn. key(), Fn. value(), mapFactory); } else { return s.toMultimap(Fn. key(), Fn. value(), mapFactory); } } /** * * @param keyExtractor * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported 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) */ @ParallelSupported 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) */ @SequentialOnly 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) */ @SequentialOnly 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 */ @SequentialOnly 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); } @ParallelSupported public Map.Entry reduce(final Map.Entry identity, final BinaryOperator> accumulator) { return s.reduce(identity, accumulator); } @ParallelSupported public Optional> reduce(final BinaryOperator> accumulator) { return s.reduce(accumulator); } @ParallelSupported public U reduce(final U identity, final BiFunction, U> accumulator, final BinaryOperator combiner) { return s.reduce(identity, accumulator, combiner); } @Deprecated @ParallelSupported public U reduce(final U identity, final BiFunction, U> accumulator) { return s.reduce(identity, accumulator); } @ParallelSupported public R collect(final Supplier supplier, final BiConsumer> accumulator, final BiConsumer combiner) { return s.collect(supplier, accumulator, combiner); } @ParallelSupported public R collect(final Supplier supplier, final BiConsumer> accumulator) { return s.collect(supplier, accumulator); } @ParallelSupported public R collect(final Collector, A, R> collector) { return s.collect(collector); } @ParallelSupported public R collect(final java.util.stream.Collector, A, R> collector) { return s.collect(collector); } @ParallelSupported public RR collectAndThen(final Collector, A, R> downstream, final Function finisher) { return s.collectAndThen(downstream, finisher); } @ParallelSupported public RR collectAndThen(final java.util.stream.Collector, A, R> downstream, final Function finisher) { return s.collectAndThen(downstream, finisher); } @SequentialOnly public String join(CharSequence delimiter) { return join(delimiter, "", ""); } @SequentialOnly public String join(CharSequence delimiter, CharSequence prefix, CharSequence suffix) { return join(delimiter, "=", prefix, suffix); } @SequentialOnly public String join(CharSequence delimiter, CharSequence keyValueDelimiter) { return join(delimiter, keyValueDelimiter, "", ""); } @SequentialOnly public String join(CharSequence delimiter, CharSequence keyValueDelimiter, CharSequence prefix, CharSequence suffix) { final Joiner joiner = Joiner.with(delimiter, keyValueDelimiter, prefix, suffix).reuseStringBuilder(true); final Iterator> iter = this.iterator(); while (iter.hasNext()) { joiner.appendEntry(iter.next()); } return joiner.toString(); } @SequentialOnly public EntryStream chain(Function>, ? extends Stream>> transfer) { return of(transfer.apply(s)); } @SequentialOnly 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 EntryStream parallel(int maxThreadNum, Splitor splitor) { return of(s.parallel(maxThreadNum, splitor)); } /** * Return the underlying maxThreadNum if the stream is parallel, otherwise 1 is returned. * * @return */ public int maxThreadNum() { return s.maxThreadNum(); } /** * Return the underlying splitor if the stream is parallel, otherwise the default value splitor.ITERATOR is returned. * * @return */ public Splitor splitor() { return s.splitor(); } public boolean isParallel() { return s.isParallel(); } /** * @return * @see #mapER(Function, Function) */ @Beta @SequentialOnly 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); } /** * 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 @SequentialOnly public EntryStream mapER(final Function, KK> keyMapper, final Function, VV> 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), valueMapper.apply(t)); return entry; } }; return map(mapper); } @Beta @SequentialOnly public EntryStream mapER(final BiFunction keyMapper, final BiFunction 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(), t.getValue()), valueMapper.apply(t.getKey(), t.getValue())); return entry; } }; return map(mapper); } /** * * @param keyMapper * @return * @see #mapER(Function, Function) */ @Beta @SequentialOnly 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); } @Beta @SequentialOnly public EntryStream flattMapKeyER(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 Stream.of(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 @SequentialOnly 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); } @Beta @SequentialOnly public EntryStream flattMapValueER(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 Stream.of(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); } @SequentialOnly public EntryStream onClose(Runnable closeHandler) { return of(s.onClose(closeHandler)); } @SequentialOnly @Override public void close() { s.close(); } @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(new SimpleImmutableEntry<>(k1, v1))); } public static EntryStream of(K k1, V v1, K k2, V v2) { return of(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2))); } public static EntryStream of(K k1, V v1, K k2, V v2, K k3, V v3) { return of(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(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(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(k3, v3), new SimpleImmutableEntry<>(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(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(k3, v3), new SimpleImmutableEntry<>(k4, v4), new SimpleImmutableEntry<>(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(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(k3, v3), new SimpleImmutableEntry<>(k4, v4), new SimpleImmutableEntry<>(k5, v5), new SimpleImmutableEntry<>(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(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(k3, v3), new SimpleImmutableEntry<>(k4, v4), new SimpleImmutableEntry<>(k5, v5), new SimpleImmutableEntry<>(k6, v6), new SimpleImmutableEntry<>(k7, v7))); } static EntryStream of(final Stream> s) { return new EntryStream(s); } public static EntryStream of(final Map map) { return new EntryStream(map, Stream.of(map)); } public static EntryStream of(final Iterator> iterator) { return new EntryStream(Stream.of(iterator)); } 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 T[] a, final Function keyExtractor) { final Function valueMapper = Fn.identity(); return Stream.of(a).mapToEntry(keyExtractor, valueMapper); } 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 Iterator iter, final Function keyExtractor) { final Function valueMapper = Fn.identity(); return Stream.of(iter).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 = Fn.entry(); 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 = Fn.entry(); 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 = Fn.entry(); 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 = Fn.entry(); final Function, Map.Entry> mapper = Fn.identity(); return Stream.zip(keys, values, valueForNonKey, valueForNonValue, zipFunction).mapToEntry(mapper); } 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; } } }