Java8ストリームをGuavaImmutableCollectionに収集するにはどうすればよいですか?


82

私は次のことをしたいと思います:

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

しかし、結果のリストがGuavaの実装であるようにImmutableList

私は私ができることを知っています

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

でも直接集めたいです。私はもう試した

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

しかし、それは例外を投げました:

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

回答:


89

toImmutableList()Alexisの承認された回答のメソッドは、Guava 21に含まれ、次の ように使用できます。

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

編集:リリース27.16242bdd)で他の頻繁に使用されるAPIとともに削除さ@Betaれました。ImmutableList.toImmutableList


1
@Betaとしてマークされたメソッド。それで、それはドキュメントによって事前に推奨されていませんか?
user26028 0719年

まだ@Betaグアバ26.0の時点で。
パーランドバーグ

見方を変えると、Googleは2004年から2009年までGmailをベータタグの下に置いていました。これは2004年の発売時にすでにかなり安定した成熟した製品でした。Googleは一般にベータステータスから製品を宣伝することにかなり消極的です。ほぼコメディーのポイントに。
anataliocs

68

これはcollectingAndThenコレクターが役立つところです:

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

List構築したばかりの変換を適用します。結果としてImmutableList


または、に直接収集して、最後にBuilder呼び出すこともできますbuild()

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

このオプションが少し冗長で、多くの場所で使用したい場合は、独自のコレクターを作成できます。

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

その後:

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

コメントにリンクが表示されなくなった場合に備えて。私の2番目のアプローチは、単にを使用する静的ユーティリティメソッドで定義できますCollector.of。独自の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);
}

と使用法:

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

3
これでも中間リストが作成されますね。私はそれを避けたいと思います。でしたImmutableList.Builder任意の助けになりますか?
ゾルタン2015年

4
@Zoltán値をビルダーに直接蓄積して(編集を参照)、を呼び出すことができますbuild()
Alexis C.

4
この詳細な回答をありがとうございます。:現在対処されているようだgithub.com/google/guava/issues/1582、ここでは良い例(あなたが提案するもののようにたくさん)もあります:gist.github.com/JakeWharton/9734167
ゾルタン

4
@Zoltánああそうです。良い発見; 2番目の選択肢をユーティリティメソッドにラップするだけです。独自のCollectorクラスを定義するよりも少し優れています:
Alexis C.

参照型はImmutableList<Integer>(の代わりにList<Integer>)である可能性があります。
palacsint 2018

17

私の質問に対する直接の答えではありませんが(コレクターを使用しません)、これは中間コレクションを使用しないかなりエレガントなアプローチです。

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

ソース


6

ところで:JDK 10以降、純粋なJavaで実行できます。

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

またtoUnmodifiableSettoUnmodifiableMap利用可能です。

コレクターの内部でそれは経由で行われました List.of(list.toArray())


1
および!= Guava'sであるため、これは正確には当てはまりません。実用的な観点からは、あなたはほとんど正しいですが、それでもあなたの答えの中でこのニュアンスに言及することは理にかなっています。ImmutableCollections.List12ImmutableCollections.ListNImmutableList
パーランドバーグ

4

参考までに、Java8を使用せずにGuavaでこれを行うための合理的な方法があります。

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

実際にListセマンティクスを必要とせずNavigableSet、を使用できる場合は、がContiguousSet実際にすべての要素(RangeDiscreteDomain)を格納する必要がないため、さらに優れています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.