> toMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
BinaryOperator mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
/**
* Returns a {@code Collector} that accumulates elements into a
* {@code Map} whose keys and values are the result of applying the provided
* mapping functions to the input elements.
*
* 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. The {@code Map}
* is created by a provided supplier function.
*
* @implNote
* The returned {@code Collector} is not concurrent. For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation. If it is
* not required that results are merged into the {@code Map} in encounter
* order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
* may offer better parallel performance.
*
* @param the type of the input elements
* @param the output type of the key mapping function
* @param the output type of the value mapping function
* @param the type of the resulting {@code Map}
* @param keyMapper a mapping function to produce keys
* @param valueMapper a mapping function to produce values
* @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)}
* @param mapSupplier a function which returns a new, empty {@code Map} into
* which the results will be inserted
* @return a {@code Collector} which collects elements into a {@code Map}
* whose keys are the result of applying a key mapping function to the input
* elements, and whose values are the result of applying a value mapping
* function to all input elements equal to the key and combining them
* using the merge function
*
* @see #toMap(Function, Function)
* @see #toMap(Function, Function, BinaryOperator)
* @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
*/
public static >
Collector toMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
BinaryOperator mergeFunction,
Supplier mapSupplier) {
BiConsumer accumulator
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
/**
* Returns a concurrent {@code Collector} that accumulates elements into a
* {@code ConcurrentMap} whose keys and values are the result of applying
* the provided mapping functions to the input elements.
*
* If the mapped keys contains duplicates (according to
* {@link Object#equals(Object)}), an {@code IllegalStateException} is
* thrown when the collection operation is performed. If the mapped keys
* may have duplicates, use
* {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead.
*
* @apiNote
* It is common for either the key or the value to be the input elements.
* In this case, the utility method
* {@link java.util.function.Function#identity()} may be helpful.
* For example, the following produces a {@code Map} mapping
* students to their grade point average:
*
{@code
* Map studentToGPA
* students.stream().collect(toMap(Functions.identity(),
* student -> computeGPA(student)));
* }
* And the following produces a {@code Map} mapping a unique identifier to
* students:
* {@code
* Map studentIdToStudent
* students.stream().collect(toConcurrentMap(Student::getId,
* Functions.identity());
* }
*
* This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
* {@link Collector.Characteristics#UNORDERED unordered} Collector.
*
* @param the type of the input elements
* @param the output type of the key mapping function
* @param the output type of the value mapping function
* @param keyMapper the mapping function to produce keys
* @param valueMapper the mapping function to produce values
* @return a concurrent, unordered {@code Collector} which collects elements into a
* {@code ConcurrentMap} whose keys are the result of applying a key mapping
* function to the input elements, and whose values are the result of
* applying a value mapping function to the input elements
*
* @see #toMap(Function, Function)
* @see #toConcurrentMap(Function, Function, BinaryOperator)
* @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
*/
public static
Collector> toConcurrentMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper) {
return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new);
}
/**
* Returns a concurrent {@code Collector} that accumulates elements into a
* {@code ConcurrentMap} whose keys and values are the result of applying
* the provided mapping functions to the input elements.
*
* 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.
*
* @apiNote
* There are multiple ways to deal with collisions between multiple elements
* mapping to the same key. The other forms of {@code toConcurrentMap} simply use
* a merge function that throws unconditionally, but you can easily write
* more flexible merge policies. For example, if you have a stream
* of {@code Person}, and you want to produce a "phone book" mapping name to
* address, but it is possible that two persons have the same name, you can
* do as follows to gracefully deals with these collisions, and produce a
* {@code Map} mapping names to a concatenated list of addresses:
*
{@code
* Map phoneBook
* people.stream().collect(toConcurrentMap(Person::getName,
* Person::getAddress,
* (s, a) -> s + ", " + a));
* }
*
* This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
* {@link Collector.Characteristics#UNORDERED unordered} Collector.
*
* @param the type of the input elements
* @param the output type of the key mapping function
* @param the output type of the value mapping function
* @param keyMapper a mapping function to produce keys
* @param valueMapper a mapping function to produce values
* @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 concurrent, unordered {@code Collector} which collects elements into a
* {@code ConcurrentMap} whose keys are the result of applying a key mapping
* function to the input elements, and whose values are the result of
* applying a value mapping function to all input elements equal to the key
* and combining them using the merge function
*
* @see #toConcurrentMap(Function, Function)
* @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
* @see #toMap(Function, Function, BinaryOperator)
*/
public static
Collector>
toConcurrentMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
BinaryOperator mergeFunction) {
return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new);
}
/**
* Returns a concurrent {@code Collector} that accumulates elements into a
* {@code ConcurrentMap} whose keys and values are the result of applying
* the provided mapping functions to the input elements.
*
* 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. The
* {@code ConcurrentMap} is created by a provided supplier function.
*
*
This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
* {@link Collector.Characteristics#UNORDERED unordered} Collector.
*
* @param the type of the input elements
* @param the output type of the key mapping function
* @param the output type of the value mapping function
* @param the type of the resulting {@code ConcurrentMap}
* @param keyMapper a mapping function to produce keys
* @param valueMapper a mapping function to produce values
* @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)}
* @param mapSupplier a function which returns a new, empty {@code Map} into
* which the results will be inserted
* @return a concurrent, unordered {@code Collector} which collects elements into a
* {@code ConcurrentMap} whose keys are the result of applying a key mapping
* function to the input elements, and whose values are the result of
* applying a value mapping function to all input elements equal to the key
* and combining them using the merge function
*
* @see #toConcurrentMap(Function, Function)
* @see #toConcurrentMap(Function, Function, BinaryOperator)
* @see #toMap(Function, Function, BinaryOperator, Supplier)
*/
public static >
Collector toConcurrentMap(Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
BinaryOperator mergeFunction,
Supplier mapSupplier) {
BiConsumer accumulator
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID);
}
/**
* Returns a {@code Collector} which applies an {@code int}-producing
* mapping function to each input element, and returns summary statistics
* for the resulting values.
*
* @param the type of the input elements
* @param mapper a mapping function to apply to each element
* @return a {@code Collector} implementing the summary-statistics reduction
*
* @see #summarizingDouble(ToDoubleFunction)
* @see #summarizingLong(ToLongFunction)
*/
public static
Collector summarizingInt(ToIntFunction super T> mapper) {
return new CollectorImpl(
IntSummaryStatistics::new,
(r, t) -> r.accept(mapper.applyAsInt(t)),
(l, r) -> { l.combine(r); return l; }, CH_ID);
}
/**
* Returns a {@code Collector} which applies an {@code long}-producing
* mapping function to each input element, and returns summary statistics
* for the resulting values.
*
* @param the type of the input elements
* @param mapper the mapping function to apply to each element
* @return a {@code Collector} implementing the summary-statistics reduction
*
* @see #summarizingDouble(ToDoubleFunction)
* @see #summarizingInt(ToIntFunction)
*/
public static
Collector summarizingLong(ToLongFunction super T> mapper) {
return new CollectorImpl(
LongSummaryStatistics::new,
(r, t) -> r.accept(mapper.applyAsLong(t)),
(l, r) -> { l.combine(r); return l; }, CH_ID);
}
/**
* Returns a {@code Collector} which applies an {@code double}-producing
* mapping function to each input element, and returns summary statistics
* for the resulting values.
*
* @param the type of the input elements
* @param mapper a mapping function to apply to each element
* @return a {@code Collector} implementing the summary-statistics reduction
*
* @see #summarizingLong(ToLongFunction)
* @see #summarizingInt(ToIntFunction)
*/
public static
Collector summarizingDouble(ToDoubleFunction super T> mapper) {
return new CollectorImpl(
DoubleSummaryStatistics::new,
(r, t) -> r.accept(mapper.applyAsDouble(t)),
(l, r) -> { l.combine(r); return l; }, CH_ID);
}
/**
* Implementation class used by partitioningBy.
*/
private static final class Partition
extends AbstractMap
implements Map {
final T forTrue;
final T forFalse;
Partition(T forTrue, T forFalse) {
this.forTrue = forTrue;
this.forFalse = forFalse;
}
@Override
public Set