क्या कोई जावा # C 'उपज' कीवर्ड के बराबर है?


112

मुझे पता है कि जावा में कोई सीधा बराबर नहीं है, लेकिन शायद एक तीसरी पार्टी है?

यह वास्तव में सुविधाजनक है। वर्तमान में मैं एक ट्रीटर को लागू करना चाहता हूं जो एक पेड़ में सभी नोड्स पैदा करता है, जो उपज के साथ कोड की पांच पंक्तियों के बारे में है।


6
मैं जानता हूँ मैं जानता हूँ। लेकिन मुझे लगता है कि अधिक भाषाओं को जानना अधिक शक्ति है। इसके अलावा, कंपनी में बैकेंड डेवलपमेंट (जो मैं कर रहा हूं) मैं अभी जावा में काम कर रहा हूं, इसलिए मैं वास्तव में भाषा का चयन नहीं कर सकता :(
ripper234

जवाबों:


91

दो विकल्प मुझे पता है कि 2007 से एवाड बेन डोव के इन्फोमेंसर-संग्रह पुस्तकालय और 2008 से जिम ब्लैकलर की यील्डएडैप्टर लाइब्रेरी है (जो अन्य उत्तर में भी वर्णित है)।

दोनों आपको yield returnजावा में समान निर्माण के साथ कोड लिखने की अनुमति देंगे , इसलिए दोनों आपके अनुरोध को पूरा करेंगे। दोनों के बीच उल्लेखनीय अंतर हैं:

यांत्रिकी

जिम की मल्टीथ्रेडिंग का उपयोग करते हुए एवाड की लाइब्रेरी बायटेकोड हेरफेर का उपयोग कर रही है। आपकी आवश्यकताओं के आधार पर, प्रत्येक के अपने फायदे और नुकसान हो सकते हैं। यह संभावना है कि एवाड का समाधान तेज है, जबकि जिम अधिक पोर्टेबल है (उदाहरण के लिए, मुझे नहीं लगता कि एवाड की लाइब्रेरी एंड्रॉइड पर काम करेगी)।

इंटरफेस

अविद की लाइब्रेरी में एक क्लीनर इंटरफ़ेस है - यहाँ एक उदाहरण है:

Iterable<Integer> it = new Yielder<Integer>() {
    @Override protected void yieldNextCore() {
        for (int i = 0; i < 10; i++) {
            yieldReturn(i);
            if (i == 5) yieldBreak();
        }
    }
};

जबकि जिम अधिक जटिल है, आपको adeptएक जेनेरिक की आवश्यकता है Collectorजो एक collect(ResultHandler)विधि है ... उह। हालाँकि, आप ज़ूम इनफॉर्मेशन द्वारा जिम के कोड के आसपास इस रैपर जैसे कुछ का उपयोग कर सकते हैं जो कि बहुत सरल करता है:

Iterable<Integer> it = new Generator<Integer>() {
    @Override protected void run() {
        for (int i = 0; i < 10; i++) {
            yield(i);
            if (i == 5) return;
        }
    }
};

लाइसेंस

एविएड का समाधान बीएसडी है।

जिम का समाधान सार्वजनिक डोमेन है, और इसलिए इसका आवरण ऊपर वर्णित है।


3
शानदार जवाब। न केवल आपने प्रश्न का पूरी तरह से उत्तर दिया, आपने बहुत स्पष्ट तरीके से ऐसा किया। इसके अलावा, मुझे आपके उत्तर का प्रारूप पसंद है और आपने लाइसेंस जानकारी को कैसे शामिल किया है। कमाल का जवाब देते रहो! :)
मैल्कम

1
अमरूद मत भूलना AbstractIterator
shmosel

मैंने अभी एक और (MIT- लाइसेंस प्राप्त) समाधान प्रकाशित किया है, जो निर्माता के लिए एक अलग थ्रेड लॉन्च करता है, और निर्माता और उपभोक्ता के बीच एक बंधी हुई कतार को स्थापित करता है: github.com/lukehutch/Producer
ल्यूक हचिसन

ध्यान दें कि yield(i)JDK 13 के रूप में टूट जाएगा, क्योंकि yieldएक नया जावा स्टेटमेंट / आरक्षित कीवर्ड के रूप में जोड़ा जा रहा है।
ल्यूक हचिसन

14

इन दोनों दृष्टिकोणों को थोड़ा साफ किया जा सकता है अब जावा में लैम्ब्डा है। आप कुछ ऐसा कर सकते हैं

public Yielderable<Integer> oneToFive() {
    return yield -> {
        for (int i = 1; i < 10; i++) {
            if (i == 6) yield.breaking();
            yield.returning(i);
        }
    };
}

मैंने यहाँ थोड़ा और समझाया।


4
Yielderable? यह सिर्फ नहीं होना चाहिए Yieldable? (क्रिया सिर्फ 'उपज' किया जा रहा है, नहीं 'yielder' या 'yielderate' या जो कुछ भी)
Jochem Kuijpers

yield -> { ... }JDK 13 के रूप में टूट जाएगा, क्योंकि yieldएक नया जावा स्टेटमेंट / आरक्षित कीवर्ड के रूप में जोड़ा जा रहा है।
ल्यूक हचिसन

1

मुझे पता है कि यह एक बहुत पुराना सवाल है, और ऊपर वर्णित दो तरीके हैं:

  • पोर्टिंग के दौरान यह इतना आसान नहीं है कि बाइटकोड हेरफेर;
  • थ्रेड-आधारित yieldजो स्पष्ट रूप से संसाधन लागत है।

हालांकि, yieldजावा में जनरेटर को लागू करने का एक और, तीसरा और शायद सबसे प्राकृतिक तरीका है, जो कि सी # 2.0+ कंपाइलरों को yield return/breakपीढ़ी के लिए क्या करता है के लिए निकटतम कार्यान्वयन है : लोमबोक-पीजी । यह पूरी तरह से एक राज्य मशीन पर आधारित है, और javacस्रोत कोड एएसटी में हेरफेर करने के लिए तंग सहयोग की आवश्यकता है । दुर्भाग्य से, लुम्बोक-पीजी समर्थन को बंद किया जा रहा है (एक या दो साल से अधिक के लिए कोई रिपॉजिटरी गतिविधि नहीं है), और मूल प्रोजेक्ट लोम्बोक में दुर्भाग्य से इस yieldसुविधा का अभाव है (इसमें ग्रहण, इंटेलीजेंट आईडीईए समर्थन की तरह बेहतर आईडीई है, हालांकि)।


1

Stream.iterate (बीज, seedOperator) .limit (एन) .foreach (कार्रवाई) उपज ऑपरेटर के रूप में ही नहीं है, लेकिन यह अपने स्वयं के जनरेटर इस तरह से लिखने के लिए उपयोगी हो सकता है:

import java.util.stream.Stream;
public class Test01 {
    private static void myFoo(int someVar){
        //do some work
        System.out.println(someVar);
    }
    private static void myFoo2(){
        //do some work
        System.out.println("some work");
    }
    public static void main(String[] args) {
        Stream.iterate(1, x -> x + 1).limit(15).forEach(Test01::myFoo);     //var1
        Stream.iterate(1, x -> x + 1).limit(10).forEach(item -> myFoo2());  //var2
    }
}

0

मैं यह भी सुझाव देता हूं कि यदि आप पहले से ही " येल्डर " के रूप में एक ऑब्जर्वेबल का उपयोग करने के लिए आरएक्सजाव का उपयोग कर रहे हैं । यदि आप अपने खुद के ऑब्जर्वेबल बनाते हैं तो इसका उपयोग इसी तरह से किया जा सकता है।

public class Example extends Observable<String> {

    public static void main(String[] args) {
        new Example().blockingSubscribe(System.out::println); // "a", "b", "c", "d"
    }

    @Override
    protected void subscribeActual(Observer<? super String> observer) {
        observer.onNext("a"); // yield
        observer.onNext("b"); // yield
        observer.onNext("c"); // yield
        observer.onNext("d"); // yield
        observer.onComplete(); // finish
    }
}

वेधशालाओं को पुनरावृत्तियों में बदला जा सकता है, ताकि आप उन्हें लूप के लिए अधिक पारंपरिक रूप में भी उपयोग कर सकें। इसके अलावा RXJava आपको वास्तव में शक्तिशाली उपकरण देता है, लेकिन अगर आपको केवल कुछ सरल की आवश्यकता है, तो शायद यह एक ओवरकिल होगा।


0

मैंने अभी एक और (MIT- लाइसेंस प्राप्त) समाधान प्रकाशित किया है , जो निर्माता को एक अलग थ्रेड में लॉन्च करता है, और निर्माता और उपभोक्ता के बीच एक बंधी हुई कतार को स्थापित करता है, जिससे निर्माता और उपभोक्ता के बीच बफरिंग, फ्लो कंट्रोल और समानांतर पाइपलाइनिंग की अनुमति मिलती है (इसलिए उपभोक्ता पिछली वस्तु का उपभोग करने पर काम कर सकता है जबकि निर्माता अगले वस्तु के उत्पादन पर काम कर रहा है)।

आप इस अनाम आंतरिक वर्ग फॉर्म का उपयोग कर सकते हैं:

Iterable<T> iterable = new Producer<T>(queueSize) {
    @Override
    public void producer() {
        produce(someT);
    }
};

उदाहरण के लिए:

for (Integer item : new Producer<Integer>(/* queueSize = */ 5) {
    @Override
    public void producer() {
        for (int i = 0; i < 20; i++) {
            System.out.println("Producing " + i);
            produce(i);
        }
        System.out.println("Producer exiting");
    }
}) {
    System.out.println("  Consuming " + item);
    Thread.sleep(200);
}

या आप बॉयलरप्लेट में कटौती करने के लिए लैम्बडा नोटेशन का उपयोग कर सकते हैं:

for (Integer item : new Producer<Integer>(/* queueSize = */ 5, producer -> {
    for (int i = 0; i < 20; i++) {
        System.out.println("Producing " + i);
        producer.produce(i);
    }
    System.out.println("Producer exiting");
})) {
    System.out.println("  Consuming " + item);
    Thread.sleep(200);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.