2016-06-09 6 views
16

मैंने जावा 8 में अपग्रेड किया और एक नए लम्दा अभिव्यक्ति के साथ एक मानचित्र के माध्यम से एक सरल पुनरावृत्ति को बदलने की कोशिश की। लूप शून्य मानों की खोज करता है और अगर कोई पाया जाता है तो अपवाद फेंकता है।मैं जावा 8 लैम्ब्डा अभिव्यक्ति में अपवाद क्यों नहीं डाल सकता?

myMap.forEach((k,v) -> { 
    if(v == null) { 
     // OK 
     System.out.println("Key '" + k+ "' not found!"); 

     // NOK! Unhandled exception type! 
     throw new MyException("Key '" + k + "' not found!"); 
    } 
}); 

किसी को भी व्याख्या कर सकते हैं क्यों throw बयान यहाँ की अनुमति दी है और कैसे इस सकता है नहीं:

for (Map.Entry<String, String> entry : myMap.entrySet()) { 
    if(entry.getValue() == null) { 
     throw new MyException("Key '" + entry.getKey() + "' not found!"); 
    } 
} 

और जावा 8 में बदलने के लिए मेरे प्रयास इस तरह दिखता है: पुराने जावा 7 कोड इस तरह दिखता है सही किया जाना चाहिए?

ग्रहण के जल्दी ठीक सुझाव मेरे लिए सही नहीं लगता है ... यह बस एक try-catch ब्लॉक के साथ throw बयान चारों ओर से घेरे:

myMap.forEach((k,v) -> { 
    if(v == null) { 
     try { 
      throw new MyException("Key '" + k + "' not found!"); 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
}); 
+12

एक बहुत ही सरल जवाब है: लैम्ब्डा भाव एक कार्यात्मक इंटरफ़ेस को लागू करने का एक संक्षिप्त साधन हैं। एक इंटरफ़ेस को लागू करने के किसी भी अन्य तरीके की तरह, आपको इंटरफ़ेस अनुबंध के अनुरूप होना चाहिए - जिसका अर्थ है कि आप केवल लक्ष्य प्रकार द्वारा अनुमत अपवादों को फेंक सकते हैं। यहां कोई जादू नहीं है। –

उत्तर

29

आप जांचे हुए अपवादों फेंकने के लिए अनुमति नहीं है क्योंकि में void accept(T t, U u) विधि BiConsumer<T, U> इंटरफ़ेस कोई अपवाद नहीं फेंकता है। और, जैसा कि आप जानते हैं, forEach इस तरह का प्रकार लेता है।

public void forEach(BiConsumer<? super K, ? super V> action) { ... } 
         | 
         V 
@FunctionalInterface 
public interface BiConsumer<T, U> { 
    void accept(T t, U u); // <-- does throw nothing 
} 

यह सच है जब हम चेक अपवादों के बारे में बात कर रहे हैं।

new HashMap<String, String>() 
    .forEach((a, b) -> { throw new IllegalArgumentException(); }); 
+3

मैं इस उत्तर से काफी सहमत हूं। जावाडॉक्स के बारे में भ्रमित बात यह है कि "कार्रवाई द्वारा फेंकने वाले अपवाद कॉलर को रिले किया जाता है।" एक साइड नोट के रूप में, एक लैम्ब्डा के भीतर अपवाद फेंकने की ज़रूरत है, बस इस विशेष मामले में नहीं। – micker

+0

वही चीज़ जो मैंने अनुभव की है। चेक अपवाद की अनुमति नहीं है। – lwpro2

+0

@ मिकर यह इंगित करने योग्य हो सकता है: वह कथन केवल 'Iterable ' इंटरफ़ेस के 'प्रत्येक' डिफ़ॉल्ट सदस्य विधि से जुड़ा हुआ है। प्राथमिक स्ट्रीम/उपभोक्ता 'Each' चेक अपवाद व्यवहार के बारे में कुछ भी दस्तावेज नहीं करता है (हालांकि कुछ निष्कर्ष फ़ंक्शन हस्ताक्षर से खींचे जा सकते हैं)। –

18

आप lambdas में अपवाद फेंक कर सकते हैं: लेकिन तुम, उदाहरण के लिए, एक अनियंत्रित अपवाद फेंक एक IllegalArgumentException की अनुमति है।

लैम्बडा द्वारा कार्यान्वित कार्यात्मक इंटरफेस के रूप में एक लैम्ब्डा को उसी अपवाद को फेंकने की अनुमति है।

यदि कार्यात्मक इंटरफ़ेस की विधि में फेंकने वाला खंड नहीं है, तो लैम्ब्डा चेक किए गए अपवादों को फेंक नहीं सकता है। (आप अभी भी RuntimeExceptions फेंक सकते हैं)।

public interface BiConsumer<T, U> { 
    void accept(T t, U u); 
} 

इस कार्यात्मक इंटरफ़ेस CheckedExceptions फेंक नहीं कर सकते हैं के लिए एक लैम्ब्डा अभिव्यक्ति:


अपने विशेष मामले में, Map.forEach एक BiConsumer एक पैरामीटर के रूप का उपयोग करता है, BiConsumer के रूप में परिभाषित किया गया है।

public interface MyFunctionalInterface<T> { 
    void accept(T t) throws Exception; 
} 
: java.util.function पैकेज में परिभाषित कार्यात्मक इंटरफेस में


तरीकों अपवाद फेंक नहीं है, लेकिन यदि आप अन्य कार्यात्मक इंटरफेस का उपयोग करें या अपने खुद के अपवाद फेंकने के लिए सक्षम होने के लिए बना सकते हैं, यानी इस इंटरफेस दिया

निम्नलिखित कोड कानूनी होगा:

MyFunctionalInterface<String> f = (s)->throw new Exception("Exception thrown in lambda"); 
संबंधित मुद्दे