क्या जावा 8 में स्ट्रीम डालना संभव है?


160

क्या जावा 8 में स्ट्रीम डालना संभव है? कहो कि मेरे पास वस्तुओं की एक सूची है, मैं सभी अतिरिक्त वस्तुओं को फ़िल्टर करने के लिए ऐसा कुछ कर सकता हूं:

Stream.of(objects).filter(c -> c instanceof Client)

हालांकि इसके बाद, अगर मैं ग्राहकों के साथ कुछ करना चाहता हूं तो मुझे उनमें से प्रत्येक को शामिल करने की आवश्यकता होगी:

Stream.of(objects).filter(c -> c instanceof Client)
    .map(c -> ((Client) c).getID()).forEach(System.out::println);

यह थोड़ा बदसूरत लगता है। क्या एक पूरी धारा को एक अलग प्रकार से डालना संभव है? जैसे कलाकारों के Stream<Object>लिए Stream<Client>?

कृपया इस तथ्य को नजरअंदाज करें कि इस तरह की चीजें करने का मतलब खराब डिजाइन होगा। हम अपने कंप्यूटर विज्ञान वर्ग में इस तरह से सामान करते हैं, इसलिए मैं जावा 8 की नई विशेषताओं को देख रहा था और अगर यह संभव था तो उत्सुक था।


3
जावा रनटाइम के दृष्टिकोण से दो स्ट्रीम प्रकार पहले से ही समान हैं, इसलिए किसी भी कलाकारों की आवश्यकता नहीं है। चाल को कंपाइलर के पीछे ले जाना है। (यह मानते हुए कि ऐसा करने का कोई मतलब नहीं है।)
गर्म चाटना

जवाबों:


283

मुझे नहीं लगता कि ऐसा करने का कोई तरीका है। संभवतः एक क्लीनर समाधान होगा:

Stream.of(objects)
    .filter(c -> c instanceof Client)
    .map(c -> (Client) c)
    .map(Client::getID)
    .forEach(System.out::println);

या, जैसा कि टिप्पणियों में सुझाया गया है, आप castविधि का उपयोग कर सकते हैं - हालांकि पूर्व में पढ़ना आसान हो सकता है:

Stream.of(objects)
    .filter(Client.class::isInstance)
    .map(Client.class::cast)
    .map(Client::getID)
    .forEach(System.out::println);

यह बहुत ज्यादा है जो मैं देख रहा था। मुझे लगता है कि मैंने इसे अनदेखा कर दिया कि इसे ग्राहक को सौंपना mapएक वापसी होगी Stream<Client>। धन्यवाद!
फिक्शन

+1 दिलचस्प नए तरीके, हालांकि वे एक नई पीढ़ी के प्रकार (क्षैतिज, ऊर्ध्वाधर नहीं) के स्पेगेटी-कोड में प्राप्त करने का जोखिम
उठाते हैं

@LordOfThePigs हाँ यह काम करता है, हालांकि मुझे यकीन नहीं है कि कोड स्पष्ट हो जाता है। मैंने अपने उत्तर में विचार जोड़ दिया है।
अघोरियों का

38
आप इसके साथ "फिल्टर" को सरल बना सकते हैं:Stream.of(objects).filter(Client.class::isInstance).[...]
निकोलस लैब्रोट

तीर के बिना हिस्सा वास्तव में सुंदर है <3
Fabich

14

Ggovan के जवाब की तर्ज पर , मैं इस प्रकार है:

/**
 * Provides various high-order functions.
 */
public final class F {
    /**
     * When the returned {@code Function} is passed as an argument to
     * {@link Stream#flatMap}, the result is a stream of instances of
     * {@code cls}.
     */
    public static <E> Function<Object, Stream<E>> instancesOf(Class<E> cls) {
        return o -> cls.isInstance(o)
                ? Stream.of(cls.cast(o))
                : Stream.empty();
    }
}

इस सहायक समारोह का उपयोग करना:

Stream.of(objects).flatMap(F.instancesOf(Client.class))
        .map(Client::getId)
        .forEach(System.out::println);

10

पार्टी के लिए देर से, लेकिन मुझे लगता है कि यह एक उपयोगी जवाब है।

flatMap इसे करने का सबसे छोटा तरीका होगा।

Stream.of(objects).flatMap(o->(o instanceof Client)?Stream.of((Client)o):Stream.empty())

यदि oएक है Clientतो एक एकल तत्व के साथ एक स्ट्रीम बनाएँ, अन्यथा खाली स्ट्रीम का उपयोग करें। इन धाराओं को फिर एक में समतल किया जाएगा Stream<Client>


मैंने इसे लागू करने की कोशिश की, लेकिन एक चेतावनी मिली कि मेरी कक्षा "अनियंत्रित या असुरक्षित संचालन" का उपयोग करती है - क्या यह अपेक्षित है?
खौफनाक

दुर्भाग्य से हाँ। क्या आप ऑपरेटर के if/elseबजाय उपयोग करना चाहते थे ?:तो कोई चेतावनी नहीं होगी। निश्चिंत रहें आप चेतावनी को सुरक्षित रख सकते हैं।
गोचन

3
वास्तव में इस से अधिक लंबा है Stream.of(objects).filter(o->o instanceof Client).map(o -> (Client)o)या यहां तक कि Stream.of(objects).filter(Client.class::isInstance).map(Client.class::cast)
दिदियर एल

4

यह थोड़ा बदसूरत लगता है। क्या एक पूरी धारा को एक अलग प्रकार से डालना संभव है? जैसे कलाकारों के Stream<Object>लिए Stream<Client>?

नहीं, यह संभव नहीं होगा। यह जावा 8 में नया नहीं है। यह जेनरिक के लिए विशिष्ट है। A List<Object>एक सुपर प्रकार का नहीं है List<String>, इसलिए आप केवल a List<Object>को नहीं कर सकते List<String>

यहां भी ऐसा ही मुद्दा है। आप डाली नहीं कर सकते Stream<Object>करने के लिए Stream<Client>। बेशक आप इसे इस तरह से अप्रत्यक्ष रूप से डाल सकते हैं:

Stream<Client> intStream = (Stream<Client>) (Stream<?>)stream;

लेकिन यह सुरक्षित नहीं है, और रनटाइम में विफल हो सकता है। इसका मूल कारण है, जावा में जेनेरिक को इरेज़र का उपयोग करके लागू किया जाता है। इसलिए, Streamरनटाइम पर किस प्रकार की कोई जानकारी उपलब्ध नहीं है। सब कुछ बस है Stream

BTW, आपके दृष्टिकोण में क्या गलत है? मुझे ठीक लगता है।


2
@DR जेनेरिक को C#संशोधन के उपयोग से लागू किया जाता है, जबकि जावा में, इसे इरेज़र का उपयोग करके लागू किया जाता है। दोनों को अलग-अलग अंदाज़ में अंजाम दिया जाता है। इसलिए आप इसे दोनों भाषाओं में समान रूप से काम करने की उम्मीद नहीं कर सकते।
रोहित जैन

1
@ मैं समझता हूं कि शुरुआती जावा में जेनेरिक की अवधारणा को समझने के लिए कई मुद्दों को मिटाता है। और जब से मैं C # का उपयोग नहीं करता हूं, मैं तुलना के बारे में अधिक विस्तार में नहीं जा सकता। लेकिन इसे लागू करने के पीछे पूरी प्रेरणा इस तरह से थी कि आईएमओ जेवीएम कार्यान्वयन में बड़े बदलाव से बचता था।
रोहित जैन

1
यह "रनटाइम पर निश्चित रूप से विफल" क्यों होगा? जैसा कि आप कहते हैं कि कोई सामान्य (सामान्य) जानकारी नहीं है, इसलिए रनटाइम की जांच के लिए कुछ भी नहीं है। यह संभवतः रनटाइम में विफल हो सकता है, अगर गलत प्रकार के माध्यम से खिलाया जाता है, लेकिन उस बारे में कोई "निश्चितता" नहीं है।
हॉट लिक्स

1
@ रोहितजैन: मैं जावा की सामान्य अवधारणा की आलोचना नहीं कर रहा हूं, लेकिन यह एकल परिणाम अभी भी बदसूरत सूचकांक बनाता है ;-)
DR

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