Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Are there any Stream Collectors that return ImmutableMap? [duplicate]

Tags:

java-8

guava

I find myself wanting a variant of Collectors.toMap which returns an ImmutableMap, such that I can do:

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

(where tuple in this particular example is a Scala Tuple2)

I've just learned that such a method will be coming with Java-8 support in Guava 21 (yay!) but that sounds a good 6 months away. Does anyone know of any existing libraries (etc) which might implement this today?

ImmutableMap is not strictly required but seems the best choice as I require: lookup by key, and retaining original iteration order. Immutability is always preferred too.

Note that FluentIterable.toMap(Function) is not sufficient because I need both a key-mapping function as well as a value-mapping function.

like image 735
Luke Usherwood Avatar asked Dec 29 '15 06:12

Luke Usherwood


People also ask

Does ImmutableMap preserve order?

of() , it does not preserve ordering.

What is ImmutableMap?

ImmutableMap, as suggested by the name, is a type of Map which is immutable. It means that the content of the map are fixed or constant after declaration, that is, they are read-only. If any attempt made to add, delete and update elements in the Map, UnsupportedOperationException is thrown.

What is Java Util stream collectors?

java.util.stream.Collectors. Implementations of Collector that implement various useful reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc.


1 Answers

You don't need to write an anonymous class for this collector. You can use Collector.of instead:

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);
}

Or if you don't mind collecting the results into a mutable map first and then copy the data into an immutable map, you can use the built-in toMap collector combined with collectingAndThen:

ImmutableMap<String, String> result = 
     list.stream()
         .collect(collectingAndThen(
             toMap(
                 tuple -> tuple._1(), 
                 tuple -> tuple._2()),
             ImmutableMap::copyOf));
like image 130
Alexis C. Avatar answered Sep 18 '22 03:09

Alexis C.