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

javax.util.streamex.EntryStream Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015 Tagir Valeev
 * 
 * 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 javax.util.streamex;

import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ForkJoinPool;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collector.Characteristics;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static javax.util.streamex.StreamExInternals.*;

/**
 * A {@link Stream} of {@link Entry} objects which provides additional specific
 * functionality.
 * 
 * 

* While {@code EntryStream} implements {@code Iterable}, it is not a * general-purpose {@code Iterable} as it supports only a single * {@code Iterator}; invoking the {@link #iterator iterator} method to obtain a * second or subsequent iterator throws {@code IllegalStateException}. * * @author Tagir Valeev * * @param * the type of {@code Entry} keys * @param * the type of {@code Entry} values */ public class EntryStream extends AbstractStreamEx, EntryStream> { @SuppressWarnings("unchecked") EntryStream(Stream> stream) { super((Stream>) stream); } @Override EntryStream supply(Stream> stream) { return strategy().newEntryStream(stream); } static Consumer> toConsumer(BiConsumer action) { return entry -> action.accept(entry.getKey(), entry.getValue()); } > Consumer> toMapConsumer(M map) { return entry -> addToMap(map, entry.getKey(), Objects.requireNonNull(entry.getValue())); } static Function, ? extends R> toFunction( BiFunction mapper) { return entry -> mapper.apply(entry.getKey(), entry.getValue()); } @Override public EntryStream sequential() { return StreamFactory.DEFAULT.newEntryStream(stream.sequential()); } /** * {@inheritDoc} * *

* If this stream was created using {@link #parallel(ForkJoinPool)}, the new * stream forgets about supplied custom {@link ForkJoinPool} and its * terminal operation will be executed in common pool. */ @Override public EntryStream parallel() { return StreamFactory.DEFAULT.newEntryStream(stream.parallel()); } /** * Returns an equivalent stream that is parallel and bound to the supplied * {@link ForkJoinPool}. * *

* This is an intermediate * operation. * *

* The terminal operation of this stream or any derived stream (except the * streams created via {@link #parallel()} or {@link #sequential()} methods) * will be executed inside the supplied {@code ForkJoinPool}. If current * thread does not belong to that pool, it will wait till calculation * finishes. * * @param fjp * a {@code ForkJoinPool} to submit the stream operation to. * @return a parallel stream bound to the supplied {@code ForkJoinPool} * @since 0.2.0 */ public EntryStream parallel(ForkJoinPool fjp) { return StreamFactory.forCustomPool(fjp).newEntryStream(stream.parallel()); } /** * Returns a {@link StreamEx} of strings which are created joining the keys * and values of the current stream using the specified delimiter. * *

* This is an intermediate * operation. * * @param delimiter * the delimiter to be used between key and value * @return the new stream * @since 0.2.2 */ public StreamEx join(CharSequence delimiter) { return map(entry -> new StringBuilder().append(entry.getKey()).append(delimiter).append(entry.getValue()) .toString()); } /** * Returns a {@link StreamEx} of strings which are created joining the keys * and values of the current stream using the specified delimiter, with the * specified prefix and suffix. * *

* This is an intermediate * operation. * * @param delimiter * the delimiter to be used between key and value * @param prefix * the sequence of characters to be used at the beginning of each * resulting string * @param suffix * the sequence of characters to be used at the end of each * resulting string * @return the new stream * @since 0.2.2 */ public StreamEx join(CharSequence delimiter, CharSequence prefix, CharSequence suffix) { return map(entry -> new StringBuilder(prefix).append(entry.getKey()).append(delimiter).append(entry.getValue()) .append(suffix).toString()); } /** * Returns an {@code EntryStream} consisting of the entries whose keys are * results of replacing source keys with the contents of a mapped stream * produced by applying the provided mapping function to each source key and * values are left intact. Each mapped stream is * {@link java.util.stream.BaseStream#close() closed} after its contents * have been placed into this stream. (If a mapped stream is {@code null} an * empty stream is used, instead.) * *

* This is an intermediate * operation. * * @param * The type of new keys * @param mapper * a non-interfering * , stateless * function to apply to each key which produces a stream of new * keys * @return the new stream */ public EntryStream flatMapKeys(Function> mapper) { return strategy().newEntryStream(stream.flatMap(e -> { Stream s = mapper.apply(e.getKey()); return s == null ? null : s.map(k -> new SimpleImmutableEntry(k, e.getValue())); })); } /** * Returns an {@code EntryStream} consisting of the entries whose values are * results of replacing source values with the contents of a mapped stream * produced by applying the provided mapping function to each source value * and keys are left intact. Each mapped stream is * {@link java.util.stream.BaseStream#close() closed} after its contents * have been placed into this stream. (If a mapped stream is {@code null} an * empty stream is used, instead.) * *

* This is an intermediate * operation. * * @param * The type of new values * @param mapper * a non-interfering * , stateless * function to apply to each value which produces a stream of new * values * @return the new stream */ public EntryStream flatMapValues(Function> mapper) { return strategy().newEntryStream(stream.flatMap(e -> { Stream s = mapper.apply(e.getValue()); return s == null ? null : s.map(v -> new SimpleImmutableEntry<>(e.getKey(), v)); })); } /** * Returns a stream consisting of the results of replacing each element of * this stream with the contents of a mapped stream produced by applying the * provided mapping function to each key-value pair. Each mapped stream is * closed after its contents have been placed into this stream. (If a mapped * stream is {@code null} an empty stream is used, instead.) * *

* This is an intermediate * operation. * * @param * The element type of the new stream * @param mapper * a non-interfering, stateless function to apply to each * key-value pair which produces a stream of new values * @return the new stream * @since 0.3.0 */ public StreamEx flatMapKeyValue(BiFunction> mapper) { return this. flatMap(toFunction(mapper)); } /** * Returns a new {@code EntryStream} which is a concatenation of this stream * and the stream created from the supplied map entries. * * @param map * the map to prepend to the stream * @return the new stream * @since 0.2.1 */ public EntryStream append(Map map) { return append(map.entrySet().stream()); } /** * Returns a new {@code EntryStream} which is a concatenation of this stream * and the supplied key-value pair. * * @param key * the key of the new {@code Entry} to append to this stream * @param value * the value of the new {@code Entry} to append to this stream * @return the new stream */ public EntryStream append(K key, V value) { return append(Stream.of(new SimpleImmutableEntry<>(key, value))); } /** * Returns a new {@code EntryStream} which is a concatenation of this stream * and two supplied key-value pairs. * * @param k1 * the key of the first {@code Entry} to append to this stream * @param v1 * the value of the first {@code Entry} to append to this stream * @param k2 * the key of the second {@code Entry} to append to this stream * @param v2 * the value of the second {@code Entry} to append to this stream * @return the new stream * @since 0.2.3 */ public EntryStream append(K k1, V v1, K k2, V v2) { return append(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2))); } /** * Returns a new {@code EntryStream} which is a concatenation of this stream * and three supplied key-value pairs. * * @param k1 * the key of the first {@code Entry} to append to this stream * @param v1 * the value of the first {@code Entry} to append to this stream * @param k2 * the key of the second {@code Entry} to append to this stream * @param v2 * the value of the second {@code Entry} to append to this stream * @param k3 * the key of the third {@code Entry} to append to this stream * @param v3 * the value of the third {@code Entry} to append to this stream * @return the new stream * @since 0.2.3 */ public EntryStream append(K k1, V v1, K k2, V v2, K k3, V v3) { return append(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(k3, v3))); } /** * Returns a new {@code EntryStream} which is a concatenation of the stream * created from the supplied map entries and this stream. * * @param map * the map to prepend to the stream * @return the new stream * @since 0.2.1 */ public EntryStream prepend(Map map) { return append(map.entrySet().stream()); } /** * Returns a new {@code EntryStream} which is a concatenation of the * supplied key-value pair and this stream. * * @param key * the key of the new {@code Entry} to prepend to this stream * @param value * the value of the new {@code Entry} to prepend to this stream * @return the new stream */ public EntryStream prepend(K key, V value) { return prepend(Stream.of(new SimpleImmutableEntry<>(key, value))); } /** * Returns a new {@code EntryStream} which is a concatenation of two * supplied key-value pairs and this stream. * * @param k1 * the key of the first {@code Entry} to prepend to this stream * @param v1 * the value of the first {@code Entry} to prepend to this stream * @param k2 * the key of the second {@code Entry} to prepend to this stream * @param v2 * the value of the second {@code Entry} to prepend to this * stream * @return the new stream * @since 0.2.3 */ public EntryStream prepend(K k1, V v1, K k2, V v2) { return prepend(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2))); } /** * Returns a new {@code EntryStream} which is a concatenation of three * supplied key-value pairs and this stream. * * @param k1 * the key of the first {@code Entry} to prepend to this stream * @param v1 * the value of the first {@code Entry} to prepend to this stream * @param k2 * the key of the second {@code Entry} to prepend to this stream * @param v2 * the value of the second {@code Entry} to prepend to this * stream * @param k3 * the key of the third {@code Entry} to prepend to this stream * @param v3 * the value of the third {@code Entry} to prepend to this stream * @return the new stream * @since 0.2.3 */ public EntryStream prepend(K k1, V v1, K k2, V v2, K k3, V v3) { return prepend(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(k3, v3))); } /** * Returns a stream consisting of the elements of this stream which have * distinct keys (according to object equality). * *

* For ordered streams, the selection of distinct keys is stable (for * elements with duplicating keys, the element appearing first in the * encounter order is preserved.) For unordered streams, no stability * guarantees are made. * *

* This is a stateful intermediate * operation. * * @return the new stream * @since 0.3.8 */ public EntryStream distinctKeys() { return distinct(Entry::getKey); } /** * Returns a stream consisting of the elements of this stream which have * distinct values (according to object equality). * *

* For ordered streams, the selection of distinct values is stable (for * elements with duplicating values, the element appearing first in the * encounter order is preserved.) For unordered streams, no stability * guarantees are made. * *

* This is a stateful intermediate * operation. * * @return the new stream * @since 0.3.8 */ public EntryStream distinctValues() { return distinct(Entry::getValue); } /** * Returns an {@code EntryStream} consisting of the entries whose keys are * modified by applying the given function and values are left unchanged. * *

* This is an intermediate * operation. * * @param * The type of the keys of the new stream * @param keyMapper * a non-interfering, stateless function to apply to each key * @return the new stream */ public EntryStream mapKeys(Function keyMapper) { return strategy().newEntryStream( stream.map(e -> new SimpleImmutableEntry<>(keyMapper.apply(e.getKey()), e.getValue()))); } /** * Returns an {@code EntryStream} consisting of the entries whose keys are * left unchanged and values are modified by applying the given function. * *

* This is an intermediate * operation. * * @param * The type of the values of the new stream * @param valueMapper * a non-interfering, stateless function to apply to each value * @return the new stream */ public EntryStream mapValues(Function valueMapper) { return strategy().newEntryStream( stream.map(e -> new SimpleImmutableEntry<>(e.getKey(), valueMapper.apply(e.getValue())))); } /** * Returns a {@link StreamEx} consisting of the results of applying the * given function to the keys and values of this stream. * *

* This is an intermediate * operation. * * @param * The element type of the new stream * @param mapper * a non-interfering, stateless function to apply to key and * value of each {@link Entry} in this stream * @return the new stream */ public StreamEx mapKeyValue(BiFunction mapper) { return this. map(toFunction(mapper)); } /** * Returns an {@code EntryStream} consisting of the entries whose keys are * modified by applying the given function and values are left unchanged. * *

* This is an intermediate * operation. * * @param * The type of the keys of the new stream * @param keyMapper * a non-interfering, stateless function to apply to each * key-value pair which returns the updated key * @return the new stream * @since 0.3.0 */ public EntryStream mapToKey(BiFunction keyMapper) { return strategy().newEntryStream( stream.map(e -> new SimpleImmutableEntry<>(keyMapper.apply(e.getKey(), e.getValue()), e.getValue()))); } /** * Returns an {@code EntryStream} consisting of the entries whose keys are * left unchanged and values are modified by applying the given function. * *

* This is an intermediate * operation. * * @param * The type of the values of the new stream * @param valueMapper * a non-interfering, stateless function to apply to each * key-value pair which returns the updated value * @return the new stream * @since 0.3.0 */ public EntryStream mapToValue(BiFunction valueMapper) { return strategy().newEntryStream( stream.map(e -> new SimpleImmutableEntry<>(e.getKey(), valueMapper.apply(e.getKey(), e.getValue())))); } /** * Returns a stream consisting of the {@link Entry} objects which keys are * the values of this stream elements and vice versa. * *

* This is an intermediate * operation. * * @return the new stream */ public EntryStream invert() { return strategy().newEntryStream(stream.map(e -> new SimpleImmutableEntry<>(e.getValue(), e.getKey()))); } /** * Returns a stream consisting of the elements of this stream which keys * match the given predicate. * *

* This is an intermediate * operation. * * @param keyPredicate * a non-interfering, stateless predicate to apply to the key of * each element to determine if it should be included * @return the new stream */ public EntryStream filterKeys(Predicate keyPredicate) { return filter(e -> keyPredicate.test(e.getKey())); } /** * Returns a stream consisting of the elements of this stream which values * match the given predicate. * *

* This is an intermediate * operation. * * @param valuePredicate * a non-interfering, stateless predicate to apply to the value * of each element to determine if it should be included * @return the new stream */ public EntryStream filterValues(Predicate valuePredicate) { return filter(e -> valuePredicate.test(e.getValue())); } /** * Returns a stream consisting of the elements of this stream which elements * match the given predicate. * *

* This is an intermediate * operation. * * @param predicate * a non-interfering, stateless predicate to apply to the * key-value pairs of each element to determine if it should be * included * @return the new stream * @since 0.3.0 */ public EntryStream filterKeyValue(BiPredicate predicate) { return filter(e -> predicate.test(e.getKey(), e.getValue())); } /** * Returns a stream consisting of the elements of this stream which keys * don't match the given predicate. * *

* This is an intermediate * operation. * * @param keyPredicate * a non-interfering, stateless predicate to apply to the key of * each element to determine if it should be excluded * @return the new stream */ public EntryStream removeKeys(Predicate keyPredicate) { return filterKeys(keyPredicate.negate()); } /** * Returns a stream consisting of the elements of this stream which values * don't match the given predicate. * *

* This is an intermediate * operation. * * @param valuePredicate * a non-interfering, stateless predicate to apply to the value * of each element to determine if it should be excluded * @return the new stream */ public EntryStream removeValues(Predicate valuePredicate) { return filterValues(valuePredicate.negate()); } /** * Returns a stream consisting of the elements of this stream which key is * not null. * *

* This is an intermediate * operation. * * @return the new stream */ public EntryStream nonNullKeys() { return filter(e -> e.getKey() != null); } /** * Returns a stream consisting of the elements of this stream which value is * not null. * *

* This is an intermediate * operation. * * @return the new stream */ public EntryStream nonNullValues() { return filter(e -> e.getValue() != null); } /** * 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" }) public EntryStream selectKeys(Class clazz) { return (EntryStream) filter(e -> clazz.isInstance(e.getKey())); } /** * 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" }) public EntryStream selectValues(Class clazz) { return (EntryStream) filter(e -> clazz.isInstance(e.getValue())); } /** * Returns a stream consisting of the entries of this stream, additionally * performing the provided action on each entry key as entries are consumed * from the resulting stream. * *

* This is an intermediate * operation. * *

* For parallel stream pipelines, the action may be called at whatever time * and in whatever thread the element is made available by the upstream * operation. If the action modifies shared state, it is responsible for * providing the required synchronization. * * @param keyAction * a non-interfering action to perform on the keys of the entries * as they are consumed from the stream * @return the new stream * @since 0.2.3 */ public EntryStream peekKeys(Consumer keyAction) { return peek(e -> keyAction.accept(e.getKey())); } /** * Returns a stream consisting of the entries of this stream, additionally * performing the provided action on each entry value as entries are * consumed from the resulting stream. * *

* This is an intermediate * operation. * *

* For parallel stream pipelines, the action may be called at whatever time * and in whatever thread the element is made available by the upstream * operation. If the action modifies shared state, it is responsible for * providing the required synchronization. * * @param valueAction * a non-interfering action to perform on the values of the * entries as they are consumed from the stream * @return the new stream * @since 0.2.3 */ public EntryStream peekValues(Consumer valueAction) { return peek(e -> valueAction.accept(e.getValue())); } /** * Returns a stream consisting of the entries of this stream, additionally * performing the provided action on each entry key-value pair as entries * are consumed from the resulting stream. * *

* This is an intermediate * operation. * *

* For parallel stream pipelines, the action may be called at whatever time * and in whatever thread the element is made available by the upstream * operation. If the action modifies shared state, it is responsible for * providing the required synchronization. * * @param action * a non-interfering action to perform on the keys and values of * the entries as they are consumed from the stream * @return the new stream * @since 0.2.3 */ public EntryStream peekKeyValue(BiConsumer action) { return peek(toConsumer(action)); } /** * Returns a stream consisting of the keys of this stream elements. * *

* This is an intermediate * operation. * * @return the new stream */ public StreamEx keys() { return map(Entry::getKey); } /** * Returns a stream consisting of the values of this stream elements. * *

* This is an intermediate * operation. * * @return the new stream */ public StreamEx values() { return map(Entry::getValue); } /** * Returns a {@link Map} containing the elements of this stream. There are * no guarantees on the type or serializability of the {@code Map} returned; * if more control over the returned {@code Map} is required, use * {@link #toCustomMap(Supplier)}. * *

* If the mapped keys contains duplicates (according to * {@link Object#equals(Object)}), an {@code IllegalStateException} is * thrown when the collection operation is performed. * *

* This is a terminal * operation. * *

* Returned {@code Map} is guaranteed to be modifiable. * *

* For parallel stream the concurrent {@code Map} is created. * * @return a {@code Map} containing the elements of this stream * @see Collectors#toMap(Function, Function) * @see Collectors#toConcurrentMap(Function, Function) */ public Map toMap() { Map map = stream.isParallel() ? new ConcurrentHashMap<>() : new HashMap<>(); forEach(toMapConsumer(map)); return map; } /** * Returns a {@link Map} containing the elements of this stream. There are * no guarantees on the type or serializability of the {@code Map} returned; * if more control over the returned {@code Map} is required, use * {@link #toCustomMap(BinaryOperator, Supplier)}. * *

* If the mapped keys contains duplicates (according to * {@link Object#equals(Object)}), the value mapping function is applied to * each equal element, and the results are merged using the provided merging * function. * *

* This is a terminal * operation. * *

* Returned {@code Map} is guaranteed to be modifiable. * * @param mergeFunction * a merge function, used to resolve collisions between values * associated with the same key, as supplied to * {@link Map#merge(Object, Object, BiFunction)} * @return a {@code Map} containing the elements of this stream * @throws IllegalStateException * if duplicate key was encountered in the stream * @see Collectors#toMap(Function, Function) * @see Collectors#toConcurrentMap(Function, Function) * @since 0.1.0 */ public Map toMap(BinaryOperator mergeFunction) { Function, K> keyMapper = Entry::getKey; Function, V> valueMapper = Entry::getValue; return collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new)); } /** * Returns a {@link Map} containing the elements of this stream. The * {@code Map} is created by a provided supplier function. * *

* If the mapped keys contains duplicates (according to * {@link Object#equals(Object)}), an {@code IllegalStateException} is * thrown when the collection operation is performed. * *

* This is a terminal * operation. * * @param * the type of the resulting map * @param mapSupplier * a function which returns a new, empty {@code Map} into which * the results will be inserted * @return a {@code Map} containing the elements of this stream * @see Collectors#toMap(Function, Function) * @see Collectors#toConcurrentMap(Function, Function) */ public > M toCustomMap(Supplier mapSupplier) { M map = mapSupplier.get(); if (stream.isParallel() && !(map instanceof ConcurrentMap)) { return collect(mapSupplier, (m, t) -> addToMap(m, t.getKey(), Objects.requireNonNull(t.getValue())), (m1, m2) -> m2.forEach((k, v) -> addToMap(m1, k, v))); } forEach(toMapConsumer(map)); return map; } /** * Returns a {@link Map} containing the elements of this stream. The * {@code Map} is created by a provided supplier function. * *

* If the mapped keys contains duplicates (according to * {@link Object#equals(Object)}), the value mapping function is applied to * each equal element, and the results are merged using the provided merging * function. * *

* This is a terminal * operation. * * @param * the type of the resulting map * @param mergeFunction * a merge function, used to resolve collisions between values * associated with the same key. * @param mapSupplier * a function which returns a new, empty {@code Map} into which * the results will be inserted * @return a {@code Map} containing the elements of this stream * @see Collectors#toMap(Function, Function) * @see Collectors#toConcurrentMap(Function, Function) */ public > M toCustomMap(BinaryOperator mergeFunction, Supplier mapSupplier) { Function, K> keyMapper = Entry::getKey; Function, V> valueMapper = Entry::getValue; return collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapSupplier)); } /** * Returns a {@link SortedMap} containing the elements of this stream. There * are no guarantees on the type or serializability of the {@code SortedMap} * returned; if more control over the returned {@code Map} is required, use * {@link #toCustomMap(Supplier)}. * *

* If the mapped keys contains duplicates (according to * {@link Object#equals(Object)}), an {@code IllegalStateException} is * thrown when the collection operation is performed. * *

* This is a terminal * operation. * *

* Returned {@code SortedMap} is guaranteed to be modifiable. * *

* For parallel stream the concurrent {@code SortedMap} is created. * * @return a {@code SortedMap} containing the elements of this stream * @see Collectors#toMap(Function, Function) * @see Collectors#toConcurrentMap(Function, Function) * @since 0.1.0 */ public SortedMap toSortedMap() { SortedMap map = stream.isParallel() ? new ConcurrentSkipListMap<>() : new TreeMap<>(); forEach(toMapConsumer(map)); return map; } /** * Returns a {@link SortedMap} containing the elements of this stream. There * are no guarantees on the type or serializability of the {@code SortedMap} * returned; if more control over the returned {@code Map} is required, use * {@link #toCustomMap(BinaryOperator, Supplier)}. * *

* If the mapped keys contains duplicates (according to * {@link Object#equals(Object)}), the value mapping function is applied to * each equal element, and the results are merged using the provided merging * function. * *

* This is a terminal * operation. * *

* Returned {@code SortedMap} is guaranteed to be modifiable. * * @param mergeFunction * a merge function, used to resolve collisions between values * associated with the same key, as supplied to * {@link Map#merge(Object, Object, BiFunction)} * @return a {@code SortedMap} containing the elements of this stream * @throws IllegalStateException * if duplicate key was encountered in the stream * @see Collectors#toMap(Function, Function) * @see Collectors#toConcurrentMap(Function, Function) * @since 0.1.0 */ public SortedMap toSortedMap(BinaryOperator mergeFunction) { return collect(Collectors.toMap(Entry::getKey, Entry::getValue, mergeFunction, TreeMap::new)); } public Map> grouping() { return grouping(Collectors.toList()); } public >> M grouping(Supplier mapSupplier) { return grouping(mapSupplier, Collectors.toList()); } public Map grouping(Collector downstream) { Function, K> keyMapper = Entry::getKey; Collector, ?, D> mapping = Collectors.mapping(Entry::getValue, downstream); if (stream.isParallel() && downstream.characteristics().contains(Characteristics.UNORDERED)) { return collect(Collectors.groupingByConcurrent(keyMapper, mapping)); } return collect(Collectors.groupingBy(keyMapper, mapping)); } @SuppressWarnings("unchecked") public > M grouping(Supplier mapSupplier, Collector downstream) { Function, K> keyMapper = Entry::getKey; Collector, ?, D> mapping = Collectors.mapping(Entry::getValue, downstream); if (stream.isParallel() && downstream.characteristics().contains(Characteristics.UNORDERED) && mapSupplier.get() instanceof ConcurrentMap) { return (M) collect(Collectors.groupingByConcurrent(keyMapper, (Supplier>) mapSupplier, mapping)); } return collect(Collectors.groupingBy(keyMapper, mapSupplier, mapping)); } public > Map groupingTo(Supplier collectionFactory) { return grouping(Collectors.toCollection(collectionFactory)); } public , M extends Map> M groupingTo(Supplier mapSupplier, Supplier collectionFactory) { return grouping(mapSupplier, Collectors.toCollection(collectionFactory)); } /** * Performs an action for each key-value pair of this stream. * *

* This is a terminal * operation. * *

* The behavior of this operation is explicitly nondeterministic. For * parallel stream pipelines, this operation does not guarantee to * respect the encounter order of the stream, as doing so would sacrifice * the benefit of parallelism. For any given element, the action may be * performed at whatever time and in whatever thread the library chooses. If * the action accesses shared state, it is responsible for providing the * required synchronization. * * @param action * a non-interfering action to perform on the key and value * @see #forEach(java.util.function.Consumer) */ public void forKeyValue(BiConsumer action) { forEach(toConsumer(action)); } /** * Returns an empty sequential {@code EntryStream}. * * @param * the type of stream element keys * @param * the type of stream element values * @return an empty sequential stream * @since 0.0.8 */ public static EntryStream empty() { return new EntryStream<>(Stream.empty()); } /** * Returns an {@code EntryStream} object which wraps given {@link Stream} of * {@link Entry} elements * * @param * the type of original stream keys * @param * the type of original stream values * @param stream * original stream * @return the wrapped stream */ public static EntryStream of(Stream> stream) { return new EntryStream<>(unwrap(stream)); } /** * Returns a sequential {@link EntryStream} created from given * {@link Spliterator}. * * @param * the type of stream keys * @param * the type of stream values * @param spliterator * a spliterator to create the stream from. * @return the new stream * @since 0.3.4 */ public static EntryStream of(Spliterator> spliterator) { return new EntryStream<>(StreamSupport.stream(spliterator, false)); } /** * Returns an {@code EntryStream} object which contains the entries of * supplied {@code Map}. * * @param * the type of map keys * @param * the type of map values * @param map * the map to create the stream from * @return a new {@code EntryStream} */ public static EntryStream of(Map map) { return new EntryStream<>(map.entrySet().stream()); } /** * Returns an {@code EntryStream} object whose keys are indices of given * list and the values are the corresponding list elements. * *

* The list elements are accessed using {@link List#get(int)}, so the list * should provide fast random access. The list is assumed to be unmodifiable * during the stream operations. * * @param * list element type * @param list * list to create the stream from * @return a new {@code EntryStream} * @since 0.2.3 */ public static EntryStream of(List list) { return EntryStream.of(new RangeBasedSpliterator.AsEntry<>(list)); } /** * Returns an {@code EntryStream} object whose keys are indices of given * array and the values are the corresponding array elements. * * @param * array element type * @param array * array to create the stream from * @return a new {@code EntryStream} * @since 0.2.3 */ public static EntryStream of(V[] array) { return of(Arrays.asList(array)); } /** * Returns a sequential {@code EntryStream} containing a single key-value * pair * * @param * the type of key * @param * the type of value * @param key * the key of the single element * @param value * the value of the single element * @return a singleton sequential stream */ public static EntryStream of(K key, V value) { return new EntryStream<>(Stream.of(new SimpleImmutableEntry<>(key, value))); } /** * Returns a sequential {@code EntryStream} containing two key-value pairs * * @param * the type of key * @param * the type of value * @param k1 * the key of the first element * @param v1 * the value of the first element * @param k2 * the key of the second element * @param v2 * the value of the second element * @return a sequential stream * @since 0.2.3 */ public static EntryStream of(K k1, V v1, K k2, V v2) { return new EntryStream<>(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2))); } /** * Returns a sequential {@code EntryStream} containing three key-value pairs * * @param * the type of key * @param * the type of value * @param k1 * the key of the first element * @param v1 * the value of the first element * @param k2 * the key of the second element * @param v2 * the value of the second element * @param k3 * the key of the third element * @param v3 * the value of the third element * @return a sequential stream * @since 0.2.3 */ public static EntryStream of(K k1, V v1, K k2, V v2, K k3, V v3) { return new EntryStream<>(Stream.of(new SimpleImmutableEntry<>(k1, v1), new SimpleImmutableEntry<>(k2, v2), new SimpleImmutableEntry<>(k3, v3))); } /** * Returns a sequential {@code EntryStream} containing {@code Entry} objects * composed from corresponding key and value in given two lists. * *

* The keys and values are accessed using {@link List#get(int)}, so the * lists should provide fast random access. The lists are assumed to be * unmodifiable during the stream operations. * * @param * the type of stream element keys * @param * the type of stream element values * @param keys * the list of keys, assumed to be unmodified during use * @param values * the list of values, assumed to be unmodified during use * @return a new {@code EntryStream} * @throws IllegalArgumentException * if length of the lists differs. * @see StreamEx#zip(List, List, BiFunction) * @since 0.2.1 */ public static EntryStream zip(List keys, List values) { return of(new RangeBasedSpliterator.ZipRef<>(0, checkLength(keys.size(), values.size()), SimpleImmutableEntry::new, keys, values)); } /** * Returns a sequential {@code EntryStream} containing {@code Entry} objects * composed from corresponding key and value in given two arrays. * * @param * the type of stream element keys * @param * the type of stream element values * @param keys * the array of keys * @param values * the array of values * @return a new {@code EntryStream} * @throws IllegalArgumentException * if length of the arrays differs. * @see StreamEx#zip(Object[], Object[], BiFunction) * @since 0.2.1 */ public static EntryStream zip(K[] keys, V[] values) { return zip(Arrays.asList(keys), Arrays.asList(values)); } /** * Returns a sequential ordered {@code EntryStream} containing the possible * pairs of elements taken from the provided list. * *

* Both keys and values are taken from the input list. The index of the key * is always strictly less than the index of the value. The pairs in the * stream are lexicographically ordered. For example, for the list of three * elements the stream of three elements is created: * {@code Map.Entry(list.get(0), list.get(1))}, * {@code Map.Entry(list.get(0), list.get(2))} and * {@code Map.Entry(list.get(1), list.get(2))}. The number of elements in * the resulting stream is {@code list.size()*(list.size()+1L)/2}. * *

* The list values are accessed using {@link List#get(int)}, so the list * should provide fast random access. The list is assumed to be unmodifiable * during the stream operations. * * @param * type of the list elements * @param list * a list to take the elements from * @return a new {@code EntryStream} * @see StreamEx#ofPairs(List, BiFunction) * @since 0.3.6 */ public static EntryStream ofPairs(List list) { return of(new PairPermutationSpliterator<>(list, SimpleImmutableEntry::new)); } /** * Returns a sequential ordered {@code EntryStream} containing the possible * pairs of elements taken from the provided array. * *

* Both keys and values are taken from the input array. The index of the key * is always strictly less than the index of the value. The pairs in the * stream are lexicographically ordered. For example, for the array of three * elements the stream of three elements is created: * {@code Map.Entry(array[0], array[1])}, * {@code Map.Entry(array[0], array[2])} and * {@code Map.Entry(array[1], array[2])}. The number of elements in the * resulting stream is {@code array.length*(array.length+1L)/2}.. * * @param * type of the array elements * @param array * a array to take the elements from * @return a new {@code EntryStream} * @see StreamEx#ofPairs(Object[], BiFunction) * @since 0.3.6 */ public static EntryStream ofPairs(T[] array) { return ofPairs(Arrays.asList(array)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy