8177290: add copy factory methods for unmodifiable List, Set, Map

8184690: add Collectors for collecting into unmodifiable List, Set, and Map

Reviewed-by: alanb, briangoetz, dholmes, jrose, rriggs, scolebourne
This commit is contained in:
Stuart Marks 2017-12-04 11:50:04 -08:00
parent 6d82950756
commit f4db9575d1
10 changed files with 675 additions and 153 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -116,6 +116,8 @@ public final class Collectors {
= Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
Collector.Characteristics.IDENTITY_FINISH));
static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
static final Set<Collector.Characteristics> CH_UNORDERED_NOID
= Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED));
private Collectors() { }
@ -278,6 +280,26 @@ public final class Collectors {
CH_ID);
}
/**
* Returns a {@code Collector} that accumulates the input elements into an
* <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter
* order. The returned Collector disallows null values and will throw
* {@code NullPointerException} if it is presented with a null value.
*
* @param <T> the type of the input elements
* @return a {@code Collector} that accumulates the input elements into an
* <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter order
* @since 10
*/
@SuppressWarnings("unchecked")
public static <T>
Collector<T, ?, List<T>> toUnmodifiableList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
list -> (List<T>)List.of(list.toArray()),
CH_NOID);
}
/**
* Returns a {@code Collector} that accumulates the input elements into a
* new {@code Set}. There are no guarantees on the type, mutability,
@ -305,6 +327,36 @@ public final class Collectors {
CH_UNORDERED_ID);
}
/**
* Returns a {@code Collector} that accumulates the input elements into an
* <a href="../Set.html#unmodifiable">unmodifiable Set</a>. The returned
* Collector disallows null values and will throw {@code NullPointerException}
* if it is presented with a null value. If the input contains duplicate elements,
* an arbitrary element of the duplicates is preserved.
*
* <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
* Collector.
*
* @param <T> the type of the input elements
* @return a {@code Collector} that accumulates the input elements into an
* <a href="../Set.html#unmodifiable">unmodifiable Set</a>
* @since 10
*/
@SuppressWarnings("unchecked")
public static <T>
Collector<T, ?, Set<T>> toUnmodifiableSet() {
return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
(left, right) -> {
if (left.size() < right.size()) {
right.addAll(left); return right;
} else {
left.addAll(right); return left;
}
},
set -> (Set<T>)Set.of(set.toArray()),
CH_UNORDERED_NOID);
}
/**
* Returns a {@code Collector} that concatenates the input elements into a
* {@code String}, in encounter order.
@ -1353,7 +1405,7 @@ public final class Collectors {
* <p>If the mapped keys contain 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 #toMap(Function, Function, BinaryOperator)}
* might have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
* instead.
*
* <p>There are no guarantees on the type, mutability, serializability,
@ -1410,6 +1462,45 @@ public final class Collectors {
CH_ID);
}
/**
* Returns a {@code Collector} that accumulates the input elements into an
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
* whose keys and values are the result of applying the provided
* mapping functions to the input elements.
*
* <p>If the mapped keys contain duplicates (according to
* {@link Object#equals(Object)}), an {@code IllegalStateException} is
* thrown when the collection operation is performed. If the mapped keys
* might have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)}
* to handle merging of the values.
*
* <p>The returned Collector disallows null keys and values. If either mapping function
* returns null, {@code NullPointerException} will be thrown.
*
* @param <T> the type of the input elements
* @param <K> the output type of the key mapping function
* @param <U> the output type of the value mapping function
* @param keyMapper a mapping function to produce keys, must be non-null
* @param valueMapper a mapping function to produce values, must be non-null
* @return a {@code Collector} that accumulates the input elements into an
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
* are the result of applying the provided mapping functions to the input elements
* @throws NullPointerException if either keyMapper or valueMapper is null
*
* @see #toUnmodifiableMap(Function, Function, BinaryOperator)
* @since 10
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static <T, K, U>
Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
Objects.requireNonNull(keyMapper, "keyMapper");
Objects.requireNonNull(valueMapper, "valueMapper");
return collectingAndThen(
toMap(keyMapper, valueMapper),
map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
}
/**
* Returns a {@code Collector} that accumulates elements into a
* {@code Map} whose keys and values are the result of applying the provided
@ -1473,6 +1564,51 @@ public final class Collectors {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
/**
* Returns a {@code Collector} that accumulates the input elements into an
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
* whose keys and values are the result of applying the provided
* mapping functions to the input elements.
*
* <p>If the mapped
* keys contain 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.
*
* <p>The returned Collector disallows null keys and values. If either mapping function
* returns null, {@code NullPointerException} will be thrown.
*
* @param <T> the type of the input elements
* @param <K> the output type of the key mapping function
* @param <U> the output type of the value mapping function
* @param keyMapper a mapping function to produce keys, must be non-null
* @param valueMapper a mapping function to produce values, must be non-null
* @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)},
* must be non-null
* @return a {@code Collector} that accumulates the input elements into an
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
* are the result of applying the provided mapping functions to the input elements
* @throws NullPointerException if the keyMapper, valueMapper, or mergeFunction is null
*
* @see #toUnmodifiableMap(Function, Function)
* @since 10
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static <T, K, U>
Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {
Objects.requireNonNull(keyMapper, "keyMapper");
Objects.requireNonNull(valueMapper, "valueMapper");
Objects.requireNonNull(mergeFunction, "mergeFunction");
return collectingAndThen(
toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
}
/**
* Returns a {@code Collector} that accumulates elements into a
* {@code Map} whose keys and values are the result of applying the provided