मैं जावा 8 स्ट्रीम को अमरुद इम्युनटेबल कॉलेक्शन में कैसे जमा कर सकता हूं?


82

मैं निम्नलिखित करना चाहूंगा:

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

लेकिन इस तरह से कि परिणामी सूची अमरूद का एक कार्यान्वयन है 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));

लेकिन इसने एक अपवाद को फेंक दिया:

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

जवाबों:


89

toImmutableList()एलेक्सिस के स्वीकार किए जाते हैं जवाब में विधि अब में शामिल है अमरूद 21 और रूप में इस्तेमाल किया जा सकता है:

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

संपादित करें: हटाया @Betaसे ImmutableList.toImmutableListमें अक्सर उपयोग एपीआई के साथ रिलीज 27.1 ( 6242bdd )।


1
विधि @Beta के रूप में चिह्नित की गई है। तो यह डॉक्स द्वारा पुनः प्रकाशित नहीं किया गया है?
user2602807

अभी भी @Betaअमरूद 26.0 के रूप में।
प्रति लुंडबर्ग

परिप्रेक्ष्य के लिए, Google ने 2004 और 2009 के बीच बीटा टैग के तहत Gmail रखा, जो 2004 में लॉन्च के समय पहले से ही काफी स्थिर, परिपक्व उत्पाद था। सामान्य रूप से बीटा स्थिति से उत्पादों को बढ़ावा देने के लिए Google काफी अनिच्छुक है। लगभग कॉमेडी की बात।
एनाटिक्लस

67

यह वह जगह है जहाँ 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<>());

यदि टिप्पणी में लिंक गायब हो जाता है; मेरे दूसरे दृष्टिकोण को एक स्थिर उपयोगिता विधि में परिभाषित किया जा सकता है जो बस उपयोग करता है 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किसी भी मदद का हो सकता है?
ज़ोल्टन

4
@ ज़ोल्टन आप सीधे बिल्डर में मूल्यों को जमा कर सकते हैं (संपादित करें देखें) और फिर कॉल करें build()
एलेक्सिस सी।

4
इस विस्तृत उत्तर के लिए धन्यवाद। ऐसा लगता है कि यह वर्तमान में संबोधित किया जा रहा है: github.com/google/guava/issues/1582 , यहां भी एक अच्छा उदाहरण है (बहुत कुछ जैसा आपने सुझाव दिया): gist.github.com/JakeWharton/9734167
Zoltán

4
@ ज़ोल्टन आह हाँ; अच्छा पाता है; यह बस उपयोगिता के तरीकों में दूसरा विकल्प लपेटता है। अपनी खुद की Collectorकक्षा को परिभाषित करने से थोड़ा बेहतर है :-)
एलेक्सिस सी।

संदर्भ प्रकार ImmutableList<Integer>(के बजाय List<Integer>) हो सकते हैं।
पैलसिंट

17

हालांकि मेरे सवाल का सीधा जवाब नहीं है (यह कलेक्टरों का उपयोग नहीं करता है), यह एक बहुत ही सुंदर दृष्टिकोण है जो मध्यवर्ती संग्रहों का उपयोग नहीं करता है:

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

स्रोत


6

BTW: JDK 10 के बाद से यह शुद्ध जावा में किया जा सकता है:

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

भी toUnmodifiableSetऔर toUnmodifiableMapउपलब्ध है।

कलेक्टर के अंदर के माध्यम से किया गया था List.of(list.toArray())


1
यह बिल्कुल सही नहीं है, क्योंकि ImmutableCollections.List12और ImmutableCollections.ListN! = अमरूद ImmutableList। व्यावहारिक दृष्टिकोण से आप ज्यादातर सही हैं, लेकिन यह अभी भी अपने उत्तर में इस बारीकियों का उल्लेख करने के लिए समझ में आता है।
लुंडबर्ग में

4

FYI करें, जावा 8 के बिना अमरूद में ऐसा करने का एक उचित तरीका है:

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

यदि आपको वास्तव में Listशब्दार्थ की आवश्यकता नहीं है और बस एक का उपयोग कर सकते हैं NavigableSet, तो यह और भी बेहतर है क्योंकि ContiguousSetइसमें वास्तव में सभी तत्वों को संग्रहीत नहीं करना है (बस Rangeऔर DiscreteDomain)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.