< prev index next >

src/java.base/share/classes/java/util/stream/Collectors.java

Print this page
rev 17661 : 8177290: add copy factory methods for unmodifiable List, Set, Map
8184690: add Collectors for collecting into unmodifiable List, Set, and Map
Reviewed-by: XXX

@@ -114,10 +114,12 @@
             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
     static final Set<Collector.Characteristics> CH_UNORDERED_ID
             = 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() { }
 
     /**
      * Construct an {@code IllegalStateException} with appropriate message.

@@ -277,10 +279,28 @@
                                    (left, right) -> { left.addAll(right); return left; },
                                    CH_ID);
     }
 
     /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="List.html#unmodifiable">unmodifiable</a> {@code List}.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code List}, 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,
      * serializability, or thread-safety of the {@code Set} returned; if more
      * control over the returned {@code Set} is required, use
      * {@link #toCollection(Supplier)}.

@@ -304,10 +324,37 @@
                                    },
                                    CH_UNORDERED_ID);
     }
 
     /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="Set.html#unmodifiable">unmodifiable</a> {@code Set}.
+     *
+     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
+     * Collector.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Set}
+     * @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.
      *
      * @return a {@code Collector} that concatenates the input elements into a
      * {@code String}, in encounter order

@@ -1409,10 +1456,45 @@
                                    uniqKeysMapMerger(),
                                    CH_ID);
     }
 
     /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="Map.html#unmodifiable">unmodifiable</a> {@code Map},
+     * 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
+     * may have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)}
+     * instead.
+     *
+     * @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
+     * @param valueMapper a mapping function to produce values
+     * @return a {@code Collector} which collects elements into an unmodifiable {@code Map}
+     * whose keys and values are the result of applying mapping functions to
+     * the input elements
+     *
+     * @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) {
+        return new CollectorImpl<>(() -> new ArrayList<Map.Entry<K, U>>(),
+                                   (list, t) -> list.add(Map.entry(keyMapper.apply(t), valueMapper.apply(t))),
+                                   (list1, list2) -> { list1.addAll(list2); return list1; },
+                                   list -> (Map<K,U>)Map.ofEntries(list.toArray(new Map.Entry[0])),
+                                   CH_UNORDERED_NOID);
+    }
+
+    /**
      * 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.
      *
      * <p>If the mapped

@@ -1471,10 +1553,49 @@
                                     Function<? super T, ? extends U> valueMapper,
                                     BinaryOperator<U> mergeFunction) {
         return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
     }
 
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="Map.html#unmodifiable">unmodifiable</a> {@code Map},
+     * 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.
+     *
+     * @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
+     * @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 {@code Collector} which collects elements into an unmodifiable {@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 #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) {
+        return collectingAndThen(
+                toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
+                hm -> (Map<K,U>)Map.ofEntries(hm.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
      * mapping functions to the input elements.
      *
< prev index next >