5

से अपवाद फेंकने मैं निम्नलिखित कोड है:CompletableFuture

// How to throw the ServerException? 
public void myFunc() throws ServerException{ 
    // Some code 
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> { 
     try { 
      return someObj.someFunc(); 
     } catch(ServerException ex) { 
      // throw ex; gives an error here. 
     } 
    })); 
    // Some code 
} 

someFunc() एक ServerException फेंकता है। मैं इसे यहां संभाल नहीं लेना चाहता हूं लेकिन someFunc() से अपवाद को myFunc() के कॉलर पर फेंकना चाहता हूं।

उत्तर

11

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

public void myFunc() throws ServerException { 
    // Some code 
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> { 
     try { return someObj.someFunc(); } 
     catch(ServerException ex) { throw new CompletionException(ex); } 
    }); 
    // Some code running in parallel to someFunc() 

    A resultOfA; 
    try { 
     resultOfA = a.join(); 
    } 
    catch(CompletionException ex) { 
     try { 
      throw ex.getCause(); 
     } 
     catch(Error|RuntimeException|ServerException possible) { 
      throw possible; 
     } 
     catch(Throwable impossible) { 
      throw new AssertionError(impossible); 
     } 
    } 
    // some code using resultOfA 
} 

सभी अपवाद Supplier की अतुल्यकालिक प्रसंस्करण के अंदर फेंक दिया एक में लपेटा हो जाएगी है CompletionExceptionjoin पर कॉल करते समय, ServerException को छोड़कर हम पहले ही CompletionException में लपेट चुके हैं।

CompletionException के कारण जब हम फिर से फेंक, हम अपवाद ServerException जाँच की अनियंत्रित अपवाद हैं, Error या RuntimeException, या हमारे कस्टम अर्थात् उपवर्गों सामना कर सकते हैं। उपरोक्त कोड उन सभी को एक बहु-पकड़ के साथ संभालता है जो उन्हें फिर से फेंक देगा। चूंकि घोषित रिटर्न प्रकार getCause()Throwable है, इसलिए संकलक को हमें उस प्रकार को संभालने की आवश्यकता होती है, भले ही हम पहले से ही सभी संभावित प्रकारों को संभाले हैं। सीधा-आगे समाधान यह वास्तव में असंभव फेंकने को AssertionError में लपेटना है।

वैकल्पिक रूप से, हम अपने कस्टम अपवाद के लिए एक वैकल्पिक परिणाम भविष्य इस्तेमाल कर सकते हैं:

public void myFunc() throws ServerException { 
    // Some code 
    CompletableFuture<ServerException> exception = new CompletableFuture<>(); 
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> { 
     try { return someObj.someFunc(); } 
     catch(ServerException ex) { 
      exception.complete(ex); 
      throw new CompletionException(ex); 
     } 
    }); 
    // Some code running in parallel to someFunc() 

    A resultOfA; 
    try { 
     resultOfA = a.join(); 
    } 
    catch(CompletionException ex) { 
     if(exception.isDone()) throw exception.join(); 
     throw ex; 
    } 

    // some code using resultOfA 
} 

यह समाधान अपने मूल में उनके लिपटे रूप में सभी "अप्रत्याशित" throwables फिर से फेंक देते हैं, लेकिन केवल फेंक कस्टम ServerException फॉर्म exception भविष्य के माध्यम से पारित किया गया। ध्यान दें कि हमें यह सुनिश्चित करना होगा कि दौड़ की स्थिति से बचने के लिए exception भविष्य से पूछने से पहले a पूरा हो गया है (जैसे join() पहले कॉल करना)।

+0

के लिए धन्यवाद यह बहुत अच्छा है ... – Eugene

+0

बहुत विस्तृत उत्तर। –

2

मुझे लगता है कि आप एक RuntimeException में है कि लपेट चाहिए और फेंक कि:

throw new RuntimeException(ex); 

या कई हो एक छोटे उपयोगिता में मदद मिलेगी:

static class Wrapper extends RuntimeException { 

    private Wrapper(Throwable throwable) { 
     super(throwable); 
    } 

    public static Wrapper wrap(Throwable throwable) { 
     return new Wrapper(throwable); 
    } 

    public Throwable unwrap() { 
     return getCause(); 
    } 
} 


public static void go() { 
    CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> { 
     try { 
      throw new Exception("Just because"); 
     } catch (Exception ex) { 
      throw Wrapper.wrap(ex); 
     } 
    }); 

    a.join(); 
} 

और फिर आप कर सकते थे unwrap कि ..

try { 
     go(); 
} catch (Wrapper w) { 
     throw w.unwrap(); 
} 
+0

मैं केवल एक 'ServerException' फेंक की जरूरत है। – ayushgp

+1

@ayushgp मुझे यह डिफ़ॉल्ट धाराओं के साथ नहीं दिख रहा है, क्योंकि वे चेक अपवादों की अनुमति नहीं देते हैं ... हो सकता है कि आप इसे लपेटने और अनचाहे करने के साथ ठीक रहे हों? – Eugene

+2

ऐसा लगता है कि आपकी 'go()' विधि कभी भी फेंक नहीं देगी। मुझे लगता है कि इसमें 'शामिल()' कॉल गुम है। साथ ही, 'रैपर' 'Throwable.getCause()' के साथ पहले से उपलब्ध होने से कहीं अधिक प्रदान नहीं करता है। मैं कारण को सेट किए बिना किसी अपवाद को लपेट नहीं सकता, क्योंकि यह सम्मेलन तोड़ता है और यह उचित स्टैकट्रैस प्रिंट नहीं करेगा। –

0

भले ही अन्य का जवाब बहुत अच्छा हो। लेकिन मैं आपको CompletableFuture में एक चेक-अपवाद फेंकने का एक और तरीका देता हूं।

यदि आप किसी अन्य धागे में एक CompletableFuture आह्वान करने के लिए नहीं करना चाहते हैं, तो आप इसे संभाल करने के लिए एक अनाम वर्ग का उपयोग कर सकते हैं, इस तरह कोड:

CompletableFuture<A> a = new CompletableFuture<A>() {{ 
    try { 
     complete(someObj.someFunc()); 
    } catch (ServerException ex) { 
     completeExceptionally(ex); 
    } 
}}; 

यदि आप एक आह्वान करने के लिए चाहते हैं एक और धागा में CompletableFuture, आप भी इसे संभाल करने के लिए एक अनाम वर्ग का उपयोग कर सकते हैं, लेकिन विधि चलाने runAsync द्वारा:

CompletableFuture<A> a = new CompletableFuture<A>() {{ 
    CompletableFuture.runAsync(() -> { 
     try { 
      complete(someObj.someFunc()); 
     } catch (ServerException ex) { 
      completeExceptionally(ex); 
     } 
    }); 
}}; 
+4

किसी अज्ञात सबक्लास में ऐसा करने की कोई आवश्यकता नहीं है। उपclass केवल संसाधनों को बर्बाद कर देता है। यह भी देखें [https://] [https://stackoverflow.com/a/43767613/2711488) और [यहां] (https://stackoverflow.com/a/28961083/2711488) ... – Holger

+0

@ होल्गर धन्यवाद, महोदय। मैं केवल इसे अपने दिमाग में लिखता हूं। और मैं इसे बाद में देखूंगा। –

+0

@ होल्गर सर, मैंने पाया कि आपके दो उत्तरों अलग हैं। और मैं आपके पहले व्यक्ति को पसंद करता हूं जिसे आपने इस प्रश्न में इस्तेमाल किया था। क्योंकि यह उपयोग करना आसान है और बहुत स्पष्ट है। –

संबंधित मुद्दे