< prev index next >

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

Print this page

    rev 48045 : 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

    @@ -1,7 +1,7 @@
     /*
    - * 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
      * under the terms of the GNU General Public License version 2 only, as
      * published by the Free Software Foundation.  Oracle designates this

    @@ -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,30 @@
                                        (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 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,
          * 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 +326,40 @@
                                        },
                                        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.
          *
          * @return a {@code Collector} that concatenates the input elements into a
          * {@code String}, in encounter order

    @@ -1351,11 +1403,11 @@
          * 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 #toMap(Function, Function, BinaryOperator)}
    +     * might have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
          * instead.
          *
          * <p>There are no guarantees on the type, mutability, serializability,
          * or thread-safety of the {@code Map} returned.
          *

    @@ -1409,10 +1461,49 @@
                                        uniqKeysMapMerger(),
                                        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
          * mapping functions to the input elements.
          *
          * <p>If the mapped

    @@ -1471,10 +1562,55 @@
                                         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 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
          * mapping functions to the input elements.
          *

< prev index next >