जावा 8: मैं धाराओं में अपवाद फेंकने के तरीकों के साथ कैसे काम कर सकता हूं?


172

मान लीजिए मेरे पास एक वर्ग और एक विधि है

class A {
  void foo() throws Exception() {
    ...
  }
}

अब मैं Aएक धारा द्वारा दिए गए प्रत्येक उदाहरण के लिए फू को कॉल करना चाहूंगा:

void bar() throws Exception {
  Stream<A> as = ...
  as.forEach(a -> a.foo());
}

प्रश्न: मैं अपवाद को कैसे ठीक से संभालूं? कोड मेरी मशीन पर संकलित नहीं करता है क्योंकि मैं संभव अपवादों को नहीं संभालता हूं जिन्हें फू () द्वारा फेंक दिया जा सकता है। throws Exceptionके barयहां बेकार हो रहा है। ऐसा क्यों है?



जवाबों:


141

आपको अपनी विधि कॉल को दूसरे में लपेटने की आवश्यकता है, जहां आप चेक किए गए अपवादों को नहीं फेंकते हैं । आप अभी भी कुछ भी फेंक सकते हैं जो एक उपवर्ग है RuntimeException

एक सामान्य रैपिंग मुहावरा कुछ इस तरह है:

private void safeFoo(final A a) {
    try {
        a.foo();
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

(महाप्रकार अपवाद Exceptionहै केवल , उदाहरण के रूप में इस्तेमाल किया यह अपने आप को पकड़ने की कोशिश कभी नहीं)

तो फिर तुम से कॉल करने की कर सकते हैं: as.forEach(this::safeFoo)


1
यदि आप चाहते हैं कि यह एक आवरण विधि हो तो मैं इसे स्थिर घोषित करूंगा। यह 'इस' से कुछ भी उपयोग नहीं करता है।
अँकलू

206
यह दुख की बात है कि हमें अपने मूल अपवादों का उपयोग करने के बजाय यह करना है .... ओह जावा, यह देता है और फिर दूर ले जाता है
एरिख

1
@Stephan यह उत्तर हटा दिया गया था, लेकिन यह अभी भी यहां उपलब्ध है: stackoverflow.com/a/27661562/309308
माइकल Mrozek

3
यह मेरी कंपनी में कोड समीक्षा को तुरंत विफल कर देगा: हमें अनियंत्रित अपवादों को फेंकने की अनुमति नहीं है।
स्टेलियोस एडमांटिडिस

7
@SteliosAdamantidis जो नियम अविश्वसनीय रूप से प्रतिबंधात्मक और काउंटर उत्पादक है। क्या आप जानते हैं कि सभी तरीके, सभी एप में रनटाइम अपवादों के सभी स्वादों को फेंकने के लिए अधिकृत हैं, यहां तक ​​कि आपको यह जानने के लिए भी कि (बेशक आप हैं)? क्या आपने जाँच किए गए अपवादों की अवधारणा को लागू नहीं करने के लिए जावास्क्रिप्ट पर प्रतिबंध लगाया था? यदि मैं आपका लीड डेवलपर होता, तो मैं इसके बजाय चेक अपवादों पर प्रतिबंध लगाता।
spi

35

यदि आप चाहते हैं कि आप सभी को आमंत्रित करें foo, और आप इस अपवाद को प्रचारित करना चाहते हैं (बिना लपेटे), तो आप forइसके बजाय सिर्फ जावा के लूप का उपयोग कर सकते हैं (कुछ चाल के साथ स्ट्रीम को Iterable में बदलने के बाद ):

for (A a : (Iterable<A>) as::iterator) {
   a.foo();
}

यह, कम से कम, मैं अपने JUnit परीक्षणों में क्या करता हूं, जहां मैं अपने चेक किए गए अपवादों को लपेटने की परेशानी से नहीं गुजरना चाहता हूं (और वास्तव में मेरे परीक्षणों को अलिखित मूल लोगों को फेंकना पसंद करता हूं)


16

यह सवाल थोड़ा पुराना हो सकता है, लेकिन क्योंकि मुझे लगता है कि यहां "सही" उत्तर केवल एक ही तरीका है, जो आपके कोड में बाद में छिपे हुए कुछ मुद्दों को जन्म दे सकता है। भले ही थोड़ा विवाद हो , चेक किए गए अपवाद एक कारण से मौजूद हैं।

मेरी राय में सबसे सुंदर तरीका आप पा सकते हैं कि मीशा ने यहां "8 भविष्य" में केवल क्रिया करके जावा 8 धाराओं में एग्लगेट रनटाइम अपवाद दिया था । तो आप सभी कामकाजी भागों को चला सकते हैं और एक के रूप में काम नहीं कर रहे अपवादों को इकट्ठा कर सकते हैं। अन्यथा आप उन सभी को एक सूची में एकत्र कर सकते हैं और बाद में उन्हें संसाधित कर सकते हैं।

एक समान दृष्टिकोण बेंजी वेबर से आता है । वह काम करने और काम करने वाले हिस्सों को इकट्ठा करने के लिए खुद का प्रकार बनाने का सुझाव देता है।

इनपुट मूल्यों और आउटपुट मानों के बीच एक साधारण मानचित्रण प्राप्त करने के लिए आप वास्तव में क्या चाहते हैं, इस पर निर्भर करता है कि अपवाद आपके लिए भी काम कर सकते हैं।

यदि आपको इनमें से कोई भी तरीका पसंद नहीं है, तो कम से कम एक अपवाद का उपयोग करके (मूल अपवाद के आधार पर) विचार करें।


3
इसे एक सही उत्तर के रूप में चिह्नित किया जाना चाहिए। +। लेकिन मैं यह नहीं कह सकता कि यह एक अच्छी पोस्ट है। आपको इसे बहुत विस्तृत करना चाहिए। खुद का अपवाद कैसे मदद कर सकता है? क्या हुए अपवाद हैं? आप यहां विभिन्न वेरिएंट क्यों नहीं लाए हैं? संदर्भ में सभी उदाहरण कोड होने से SO पर यहाँ भी एक निषिद्ध पद शैली मानी जाती है। आपका पाठ टिप्पणियों के एक समूह के रूप में दिखता है।
गंगनुस

2
आपको यह चुनने में सक्षम होना चाहिए कि आप उन्हें किस स्तर पर पकड़ना चाहते हैं और उसी के साथ गड़बड़ करते हैं। स्ट्रीम एपीआई को आपको अंतिम ऑपरेशन (जैसे इकट्ठा) तक अपवाद को ले जाने देना चाहिए और एक हैंडलर के साथ वहां संभालना चाहिए या अन्यथा फेंक दिया जाना चाहिए। stream.map(Streams.passException(x->mightThrowException(x))).catch(e->whatToDo(e)).collect(...)। यह अपवादों की अपेक्षा करता है और आपको उन्हें फ्यूचर की तरह संभालने की अनुमति देता है।
अनलुकू

10

मेरा सुझाव है कि Google Guava Throwables वर्ग का उपयोग करें

प्रचारित ( फेंकने योग्य)

फेंकने योग्य के रूप में प्रचार करता है-अगर यह RuntimeException या त्रुटि का एक उदाहरण है, या किसी अन्य अंतिम उपाय के रूप में, इसे RuntimeException में लपेटता है और फिर प्रचार करता है। **

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            throw Throwables.propagate(e);
        }
    });
}

अपडेट करें:

अब जब कि इसका उपयोग कम हो गया है:

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        }
    });
}

4
इस विधि को हटा दिया गया था (दुर्भाग्य से)।
रॉबर्ट वॉन

9

आप इस तरह से अपवादों को लपेट और खोल सकते हैं।

class A {
    void foo() throws Exception {
        throw new Exception();
    }
};

interface Task {
    void run() throws Exception;
}

static class TaskException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    public TaskException(Exception e) {
        super(e);
    }
}

void bar() throws Exception {
      Stream<A> as = Stream.generate(()->new A());
      try {
        as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo()
    } catch (TaskException e) {
        throw (Exception)e.getCause();
    }
}

static void wrapException(Task task) {
    try {
        task.run();
    } catch (Exception e) {
        throw new TaskException(e);
    }
}

9

आप निम्न में से एक करना चाह सकते हैं:

  • प्रचारित अपवाद की जाँच करें,
  • इसे लपेटें और अनियंत्रित अपवाद का प्रचार करें, या
  • अपवाद को पकड़ने और प्रचार बंद करो।

कई पुस्तकालय आपको आसानी से ऐसा करने देते हैं। नीचे उदाहरण मेरे NoException लाइब्रेरी का उपयोग करके लिखा गया है ।

// Propagate checked exception
as.forEach(Exceptions.sneak().consumer(A::foo));

// Wrap and propagate unchecked exception
as.forEach(Exceptions.wrap().consumer(A::foo));
as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo));

// Catch the exception and stop propagation (using logging handler for example)
as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo)));

लाइब्रेरी में अच्छा काम! मैं भी कुछ ऐसा ही लिखने वाला था।
जैस्पर डे वीट्स

2

अधिक पठनीय तरीका:

class A {
  void foo() throws MyException() {
    ...
  }
}

RuntimeExceptionइसे अतीत में लाने के लिए बस इसे छिपाएंforEach()

  void bar() throws MyException {
      Stream<A> as = ...
      try {
          as.forEach(a -> {
              try {
                  a.foo();
              } catch(MyException e) {
                  throw new RuntimeException(e);
              }
          });
      } catch(RuntimeException e) {
          throw (MyException) e.getCause();
      }
  }

हालांकि इस बिंदु पर मैं किसी के खिलाफ पकड़ नहीं बनाऊंगा, अगर वे कहते हैं कि धाराएं छोड़ें और लूप के साथ जाएं, जब तक कि:

  • आप अपनी स्ट्रीम का उपयोग नहीं कर रहे हैं Collection.stream(), यानी सीधे फॉरवर्ड ट्रांसलेशन फॉर लूप नहीं।
  • आप उपयोग करने की कोशिश कर रहे हैं parallelstream()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.