Bir Java 8 akışını Guava ImmutableCollection'a nasıl toplayabilirim?


82

Aşağıdakileri yapmak istiyorum:

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

ancak ortaya çıkan liste bir şekilde Guava'nın bir uygulamasıdır ImmutableList.

Yapabileceğimi biliyorum

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

ama doğrudan ona toplamak istiyorum. denedim

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

ama bir istisna yarattı:

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

Yanıtlar:


89

toImmutableList()Alexis kabul cevap yöntemi artık her bir Guava 21 ve olarak kullanılabilir:

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

Düzenleme: Kaldırılan @Betagelen ImmutableList.toImmutableListsık kullanılan diğer API'ler ile birlikte Release 27.1 ( 6242bdd ).


1
@Beta olarak işaretlenen yöntem. Yani doktorlar tarafından tavsiye edilen apriory değil mi?
user2602807

Hala @BetaGuava 26.0 itibariyle.
Başına Lundberg

Bakış açısına göre Google, 2004 ve 2009 yılları arasında Gmail’i bir beta etiketi altında tuttu; bu, 2004’te piyasaya sürüldüğünde zaten oldukça kararlı, olgun bir üründü. Google, genel olarak Beta statüsündeki ürünleri tanıtmak konusunda oldukça isteksizdir. Neredeyse komedi noktasına.
anataliocs

68

collectingAndThenToplayıcının yararlı olduğu yer burasıdır :

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

Dönüşümü Listyeni inşa ettiğinize uygular ; bir ImmutableList.


Ya da doğrudan toplayıp sonunda Builderarayabilirsin build():

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

Bu seçenek sizin için biraz ayrıntılıysa ve birçok yerde kullanmak istiyorsanız, kendi koleksiyoncunuzu oluşturabilirsiniz:

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

ve sonra:

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

Sadece yorumlarda bağlantının kaybolması durumunda; ikinci yaklaşımım, basitçe kullanılan statik bir fayda yöntemiyle tanımlanabilir Collector.of. Kendi Collectorsınıfınızı oluşturmaktan daha basit .

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

ve kullanım:

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

3
Bu hala bir ara liste yaratıyor, değil mi? Bundan kaçınmak isterim. Could ImmutableList.Builderherhangi bir yardımcı olmak?
Zoltán

4
@ Zoltán Değerleri doğrudan oluşturucuda biriktirebilir (düzenlemeye bakın) ve sonra çağırabilirsiniz build().
Alexis C.

4
Bu detaylı cevap için teşekkür ederim. Görünüşe göre bu konu şu anda ele alınmaktadır: github.com/google/guava/issues/1582 , burada da güzel bir örnek var (önerdiğinize çok benziyor): gist.github.com/JakeWharton/9734167
Zoltán

4
@ Zoltán Ah evet; iyi buluntular; basitçe ikinci alternatifi fayda yöntemlerine sarar. Bir kendi tanımlama daha iyi bit Collector:-) sınıfı
Alexis C'yi

Başvuru türleri ImmutableList<Integer>(yerine List<Integer>) olabilir.
palacsint

17

Soruma doğrudan bir cevap olmasa da (koleksiyoner kullanmıyor), bu, ara koleksiyon kullanmayan oldukça zarif bir yaklaşım:

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

Kaynak .


6

BTW: JDK 10'dan beri saf Java ile yapılabilir:

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

Ayrıca toUnmodifiableSetve toUnmodifiableMapmevcut.

İç kollektör aracılığıyla yapıldı List.of(list.toArray())


1
Bu tam olarak doğru değil , çünkü ImmutableCollections.List12ve ImmutableCollections.ListN! = Guava's ImmutableList. Pratik bir bakış açısından çoğunlukla haklısınız, ancak cevabınızda bu nüanstan bahsetmek yine de mantıklı olacaktır.
Başına Lundberg

4

Bilginize, Java 8 olmadan Guava'da bunu yapmanın makul bir yolu var:

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

Eğer Listanlambilime gerçekten ihtiyacınız yoksa ve sadece a kullanabiliyorsanız NavigableSet, bu daha da iyidir çünkü ContiguousSeta'nın içindeki tüm öğeleri (sadece Rangeve DiscreteDomain) depolaması gerekmez .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.