2015-12-29 10 views
8

znalazłem się chcąc wariant Collectors.toMap która zwraca ImmutableMap tak, że mogę zrobić:Java - Czy są jakieś Stream Collectors, które zwracają ImmutableMap?

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

(gdzie tuple w tym konkretnym przypadku jest Scala Tuple2)

mam just learned że takie metoda będzie pochodzić z obsługą Java-8 w Guava 21 (yay!), ale to brzmi dobrze przez 6 miesięcy. Czy ktokolwiek wie o istniejących bibliotekach (itp.), Które mogą to dzisiaj wprowadzić?

ImmutableMap nie jest ściśle wymagane, ale wydaje się najlepszym wyborem, ponieważ wymaga: wyszukiwanie według klucza i zachowywanie oryginalnego zamówienia iteracyjnego. Niezmienność jest zawsze preferowana.

Uwaga: FluentIterable.toMap(Function) jest niewystarczająca, ponieważ potrzebuję zarówno funkcji mapowania klawiszy, jak i funkcji odwzorowania wartości.

+1

Jestem zaskoczony, że nic nie widziałem w Internecie. Wyszukiwanie "guava kolektora java 8" w popularnej wyszukiwarce zwraca wiele bezpośrednio użytecznych kodów, w tym wyniki bezpośrednio w projektach Guava (jako problemy). –

+1

W tym celu udostępniliśmy 'collectingAndThen()'. –

+0

Odpowiedzi na pytanie dotyczące "ImmutableMultimap" rzeczywiście odpowiadają na moje bezpośrednie pytania. Jednak żadne z tych rozwiązań, które znalazłem w Internecie, nie zawiera doskonałego zestawu funkcji do obsługi 'ImmutableMap' - nie ma możliwości scalania-duplikatów-kluczy i/lub nie wyrzucania' IllegalStateException' (zgodnie z konwencją ustaloną przez "Collectors") –

Odpowiedz

13

Nie musisz pisać anonimowej klasy dla tego kolekcjonera. Można użyć Collector.of zamiast:

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

Lub jeśli nie przeszkadza zbieranie wyników na zmienny mapie, a następnie skopiować dane do niezmiennej mapie, można użyć wbudowanej toMap kolektora połączona z collectingAndThen :

ImmutableMap<String, String> result = 
    list.stream() 
     .collect(collectingAndThen(
      toMap(
       tuple -> tuple._1(), 
       tuple -> tuple._2()), 
      ImmutableMap::copyOf)); 
+1

Idealny :-) Nie myślałem, żeby zaglądnąć do samego interfejsu. Zdecydowanie wolę formę 'Collector.of', ponieważ stanie się ona funkcją użyteczną o nieznanym przyszłym zastosowaniu (a śledzenie źródeł rezygnacji z pamięci może być trudne później.) –

+1

Guava dostarcza teraz Collectors dla ich typów kolekcji, np. ['ImmutableList.toImmutableMap()'] (https://github.com/google/guava/blob/2909a996047e575cdac02ea1c06a93a9419271cf/guava/src/com/google/common/collect/ImmutableMap.java#L65-L82). – Jonathan

0

Ponieważ nie znalazłem jeszcze takiej biblioteki kolekcjonerskiej, udostępniam swoje pierwsze pęknięcie w konkretnym, którego potrzebowałem. Tu nie ma żadnych dzwonów ani gwizdów! (Takich jak obsługa lub łączenie zduplikowanych kluczy).

Proszę sugerować ulepszenia.

/** 
* 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(); 
     } 
    }; 
} 
Powiązane problemy