2015-03-12 11 views
56

Chciałbym wykonaj następujące czynności:Jak mogę pobrać strumień Java 8 do Guava ImmutableCollection?

List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList()); 

ale w taki sposób, że uzyskana lista jest implementacją Guava na ImmutableList.

wiem, co mogłem zrobić

List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList()); 
List<Integer> immutableList = ImmutableList.copyOf(list); 

ale chciałbym zebrać do niego bezpośrednio. Próbowałem

List<Integer> list = IntStream.range(0, 7) 
    .collect(Collectors.toCollection(ImmutableList::of)); 

ale zwrócił wyjątek:

java.lang.UnsupportedOperationException na com.google.common.collect.ImmutableCollection.add (ImmutableCollection.java:96)

Odpowiedz

50

to gdzie kolektor collectingAndThen jest przydatna:

List<Integer> list = IntStream.range(0, 7).boxed() 
       .collect(collectingAndThen(toList(), ImmutableList::copyOf)); 

Stosuje transformację do właśnie zbudowanej wersji: List; wynikiem jest ImmutableList.


Albo można bezpośrednio zbierać do Builder i nazywają build() na koniec:

List<Integer> list = IntStream.range(0, 7) 
       .collect(Builder<Integer>::new, Builder<Integer>::add, (builder1, builder2) -> builder1.addAll(builder2.build())) 
       .build(); 

Jeśli ta opcja jest nieco-gadatliwy, a ty chcesz go używać w wielu miejscach, ty można utworzyć własny kolektor:

class ImmutableListCollector<T> implements Collector<T, Builder<T>, ImmutableList<T>> { 
    @Override 
    public Supplier<Builder<T>> supplier() { 
     return Builder::new; 
    } 

    @Override 
    public BiConsumer<Builder<T>, T> accumulator() { 
     return (b, e) -> b.add(e); 
    } 

    @Override 
    public BinaryOperator<Builder<T>> combiner() { 
     return (b1, b2) -> b1.addAll(b2.build()); 
    } 

    @Override 
    public Function<Builder<T>, ImmutableList<T>> finisher() { 
     return Builder::build; 
    } 

    @Override 
    public Set<Characteristics> characteristics() { 
     return ImmutableSet.of(); 
    } 
} 

a następnie:

List<Integer> list = IntStream.range(0, 7) 
           .boxed() 
           .collect(new ImmutableListCollector<>()); 

Na wypadek gdyby link zniknął w komentarzach; moje drugie podejście można zdefiniować w statycznej metodzie użyteczności, która po prostu używa Collector.of. Jest to prostsze niż tworzenie własnej klasy Collector.

public static <T> Collector<T, Builder<T>, ImmutableList<T>> toImmutableList() { 
    return Collector.of(Builder<T>::new, Builder<T>::add, (l, r) -> l.addAll(r.build()), Builder<T>::build); 
} 

i użytkowanie:

List<Integer> list = IntStream.range(0, 7) 
           .boxed() 
           .collect(toImmutableList()); 
+3

To nadal tworzy listę pośrednią, prawda? Chciałbym tego uniknąć. Czy "ImmutableList.Builder" może pomóc? –

+3

@ Zoltán Możesz bezpośrednio gromadzić wartości w budowniczym (patrz edycja), a następnie wywołać 'build()'. –

+2

Dziękuję za tę szczegółową odpowiedź. Wygląda na to, że jest to obecnie adresowane: https://github.com/google/guava/issues/1582, jest tu również dobry przykład (bardzo podobny do tego, co sugerujesz): https://gist.github.com/ JakeWharton/9734167 –

13

Choć nie jest to bezpośrednia odpowiedź na moje pytanie (nie używać kolektorów), jest to dość elegancki podejście, które nie korzysta z kolekcji pośrednich:

Stream<Integer> stream = IntStream.range(0, 7).boxed(); 
List<Integer> list = ImmutableList.copyOf(stream.iterator()); 

Source.

3

FYI, jest to rozsądny sposób to zrobić w Guava bez Javy 8:

ImmutableSortedSet<Integer> set = ContiguousSet.create(
    Range.closedOpen(0, 7), DiscreteDomain.integers()); 
ImmutableList<Integer> list = set.asList(); 

Jeśli nie faktycznie potrzebują List semantykę i można po prostu użyć NavigableSet, to nawet lepiej ponieważ ContiguousSet robi 'Trzeba faktycznie przechowywać wszystkie elementy w nim (tylko Range i DiscreteDomain).

51

Sposób w przyjętym odpowiedź Alexis toImmutableList() jest obecnie zawarte w Guava 21 i mogą być wykorzystane jako:

ImmutableList<Integer> list = IntStream.range(0, 7).boxed().collect(ImmutableList.toImmutableList()); 
+0

Podoba mi się to podejście) – ycomp

+0

... z tym wyjątkiem, że nie mogę używać guawy 22 lub 21, ponieważ utknąłem w wieku 19 lat, ponieważ mam w bibliotece inną bibliotekę poms używając starszej wersji guawy ... ktoś wie, jak mogę go wyśledzić? – ycomp