web-dev-qa-db-fra.com

Java - Existe-t-il des collecteurs de flux qui renvoient ImmutableMap?

Je me trouve à vouloir une variante de Collectors.toMap qui retourne une ImmutableMap, telle que je puisse faire:

ImmutableMap result = list.stream().collect(MyCollectors.toImmutableMap(
    Tuple -> Tuple._1(), Tuple -> Tuple._2());

(où Tuple dans cet exemple particulier est un Scala Tuple2)

J'ai je viens d'apprendre qu'une telle méthode viendra avec la prise en charge de Java-8 dans Guava 21 (oui!), Mais cela sonne dans six mois. Est-ce que quelqu'un connaît des bibliothèques existantes (etc.) qui pourraient implémenter cela aujourd'hui?

ImmutableMap n'est pas strictement requis, mais semble le meilleur choix que je souhaite: rechercher par clé et conserver l'ordre d'itération d'origine. L'immuabilité est toujours préférée aussi.

Notez que FluentIterable.toMap(Function) n'est pas suffisant car j'ai besoin à la fois d'une fonction de mappage de touches et d'une fonction de mappage de valeurs.

11
Luke Usherwood

Vous n'avez pas besoin d'écrire une classe anonyme pour ce collecteur. Vous pouvez utiliser Collector.of à la place:

public static <T, K, V> Collector<T, ?, ImmutableMap<K,V>> toImmutableMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends V> valueMapper) {
    return Collector.of(
               ImmutableMap.Builder<K, V>::new,
               (b, e) -> b.put(keyMapper.apply(e), valueMapper.apply(e)),
               (b1, b2) -> b1.putAll(b2.build()),
               ImmutableMap.Builder::build);
}

Ou, si cela ne vous dérange pas de collecter d'abord les résultats dans une carte modifiable, puis de copier les données dans une carte immuable, vous pouvez utiliser le collecteur intégré toMap combiné à collectingAndThen:

ImmutableMap<String, String> result = 
     list.stream()
         .collect(collectingAndThen(
             toMap(
                 Tuple -> Tuple._1(), 
                 Tuple -> Tuple._2()),
             ImmutableMap::copyOf));
17
Alexis C.

Comme je n'ai pas encore trouvé une telle bibliothèque de collectionneurs, je partage ma première expérience avec celle dont j'avais besoin. Pas de cloches ni de sifflets ici! (Comme la manipulation ou la fusion de clés en double.)

N'hésitez pas à suggérer des améliorations.

/**
 * A variant of {@link Collectors#toMap(Function, Function)} for immutable maps.
 * <p>
 * Note this variant throws {@link IllegalArgumentException} upon duplicate keys, rather than
 * {@link IllegalStateException}
 * 
 * @param <T> type of the input elements
 * @param <K> output type of the key mapping function
 * @param <V> 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 a {@code Map} whose keys and values
 *         are the result of applying mapping functions to the input elements
 *         
 * @throws IllegalArgumentException upon duplicate keys
 */
public static <T, K, V> Collector<T, ?, ImmutableMap<K,V>> toImmutableMap(
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends V> valueMapper) {
    return new Collector<T, ImmutableMap.Builder<K,V>, ImmutableMap<K,V>>() {

        public Supplier<Builder<K, V>> supplier() {
            return ImmutableMap.Builder::new;
        }

        public BiConsumer<Builder<K, V>, T> accumulator() {
            return (builder, element) -> {
                K key = keyMapper.apply(element);
                V value = valueMapper.apply(element);
                builder.put(key, value);
            };
        }

        public BinaryOperator<Builder<K, V>> combiner() {
            return (b1, b2) -> {
                b1.putAll(b2.build());
                return b1;
            };
        }

        public Function<Builder<K, V>, ImmutableMap<K, V>> finisher() {
            return builder -> builder.build();
        }

        public Set<Collector.Characteristics> characteristics() {
            return ImmutableSet.of();
        }
    };
}
0
Luke Usherwood