जावा 8 लैम्ब्डा फ़ंक्शन जो अपवाद फेंकता है?


469

मुझे पता है कि एक विधि का संदर्भ कैसे बनाया जाता है जिसमें एक Stringपैरामीटर होता है और एक रिटर्न देता है int, यह है:

Function<String, Integer>

हालाँकि, यह काम नहीं करता है यदि फ़ंक्शन अपवाद को फेंकता है, तो इसे निम्न के रूप में परिभाषित करें:

Integer myMethod(String s) throws IOException

मैं इस संदर्भ को कैसे परिभाषित करूंगा?





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

5
जूल लाइब्रेरी के बारे में क्या ? cf org.jooq.lambda.Unchecked पैकेज
chaiyachaiya

जवाबों:


401

आपको निम्न में से एक करना होगा।

  • यदि यह आपका कोड है, तो अपने स्वयं के कार्यात्मक इंटरफ़ेस को परिभाषित करें जो चेक किए गए अपवाद को घोषित करता है:

    @FunctionalInterface
    public interface CheckedFunction<T, R> {
       R apply(T t) throws IOException;
    }

    और इसका उपयोग करें:

    void foo (CheckedFunction f) { ... }
  • अन्यथा, Integer myMethod(String s)एक विधि में लपेटें जो एक चेक किए गए अपवाद की घोषणा नहीं करता है:

    public Integer myWrappedMethod(String s) {
        try {
            return myMethod(s);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    और फिर:

    Function<String, Integer> f = (String t) -> myWrappedMethod(t);

    या:

    Function<String, Integer> f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };

7
आप वास्तव में विस्तारित कर सकते हैं Consumerया Functionयदि आप डिफ़ॉल्ट विधियों का उपयोग करते हैं - नीचे मेरा उत्तर देखें।
JLB

2
मुझे लगता है कि यह एक-लाइनर के रूप में पूरा किया जा सकता है ।
नेड ट्विग

6
लघु अनुकूलन: इसके बजाय (String t) -> myWrappedMethod(t), विधि संदर्भ this::myWrappedMethodका भी उपयोग किया जा सकता है।
क्लैशसॉफ्ट

8
यह करने के लिए एक और भी अधिक सामान्य तरीका यह है कि इस @FunctionalInterface सार्वजनिक इंटरफ़ेस CheckedFunction की तरह चेक किए गए फ़ंक्शन को परिभाषित करना है <T, R, E का विस्तार अपवाद> {R लागू (T t) फेंकता है E; } इस तरह से आप यह भी परिभाषित कर सकते हैं कि फ़ंक्शन किस अपवाद को फेंक रहा है और किसी भी कोड के लिए इंटरफ़ेस का पुन: उपयोग कर सकता है।
मार्टिन ओढालियस

3
वाह। जावा मेरे विचार से बदतर है
user275801

194

आप वास्तव में एक नए इंटरफ़ेस के साथ विस्तार Consumer(और Functionआदि) कर सकते हैं जो अपवादों को संभालता है - जावा 8 के डिफ़ॉल्ट तरीकों का उपयोग करके !

इस इंटरफ़ेस पर विचार करें (विस्तार Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

फिर, उदाहरण के लिए, यदि आपके पास एक सूची है:

final List<String> list = Arrays.asList("A", "B", "C");

यदि आप forEachअपवादों को फेंकने वाले कुछ कोड के साथ (उदाहरण के साथ ) इसका उपभोग करना चाहते हैं, तो आप पारंपरिक रूप से एक कोशिश या कैच सेट सेट करेंगे:

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);

लेकिन इस नए इंटरफ़ेस के साथ, आप इसे लंबोदर एक्सप्रेशन से जोड़ सकते हैं और कंपाइलर को शिकायत नहीं होगी:

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);

या यहां तक ​​कि बस इसे अधिक रसीला होने के लिए डाल दिया! "

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});

अपडेट : ऐसा लगता है कि ड्यूरियन नामक एक बहुत अच्छा उपयोगिता पुस्तकालय का हिस्सा है जिसे एरर्स कहा जाता है जिसका उपयोग इस समस्या को बहुत अधिक लचीलेपन के साथ हल करने के लिए किया जा सकता है। उदाहरण के लिए, ऊपर मेरे कार्यान्वयन में मैंने स्पष्ट रूप से त्रुटि हैंडलिंग नीति ( System.out...या) को परिभाषित किया हैthrow RuntimeException ) को , जबकि ड्यूरियन के त्रुटियां आपको उपयोगिता विधियों के एक बड़े सूट के माध्यम से मक्खी पर एक नीति लागू करने की अनुमति देती हैं। इसे साझा करने के लिए धन्यवाद , @NedTwigg !.

नमूना उपयोग:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));

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

1
कुछ समय बाद ... मैंने अनियंत्रित अपवादों का उपयोग करने का फैसला किया और किसी भी अतिरिक्त कार्यात्मक इंटरफेस या नए पुस्तकालयों का उपयोग नहीं किया -> आसान सड़क, कम टाइपिंग, तेज वितरण, यह नहीं है।
एलोपी

1
यहाँ चुपके से मुहावरे का उपयोग करते हुए एक बेहतर संस्करण है । CheckException में RuntimeException को खोलना नहीं है।
मायुई

61

मुझे लगता है कि ड्यूरियन की Errorsकक्षा ऊपर दिए गए विभिन्न सुझावों के कई पेशेवरों को जोड़ती है।

अपने प्रोजेक्ट में डूरियन को शामिल करने के लिए, आप या तो:


या आप बस RxJava का उपयोग कर सकते हैं क्योंकि धाराओं को अंतर्निहित त्रुटि से निपटने की आवश्यकता होती है और अगर आपकी पाइपलाइन में कुछ ऐसा है जो एक अपवाद को फेंकता है तो एक अच्छा मौका है जो शायद एक अवलोकन योग्य धारा है। यह भी एक पुस्तकालय के डाउनस्ट्रीम उपभोक्ताओं पर जावा 8 को मजबूर नहीं करता है।
एडम गेन

2
कृपया ध्यान दें कि जून 2016 के बाद से डूरियन के कोई नए संस्करण नहीं हैं। शो स्टॉपर नहीं है, लेकिन कुछ को ध्यान में रखना है।
इस्तवान देवई

9
ड्यूरियन अनुरक्षक यहाँ। क्या टूटा है? यदि कोई उपयोगकर्ता बग या एक महत्वपूर्ण लापता सुविधा पाता है, तो हम जल्दी से बगफिक्स जारी करेंगे। पुस्तकालय सरल है, इस प्रकार हमारे पास कोई बग रिपोर्ट नहीं है, इसलिए हमें किसी भी बगफिक्स को जारी करने की आवश्यकता नहीं है।
नेड ट्विग

28

यह जावा 8 के लिए विशिष्ट नहीं है। आप इसके समकक्ष कुछ संकलन करने की कोशिश कर रहे हैं:

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}

15
सवाल है "मैं इस संदर्भ को कैसे परिभाषित करूंगा?" । यह वास्तव में सवाल का जवाब नहीं देता है; यह स्पष्ट करता है कि समस्या क्या है।
दाऊद इब्न करीम

13

अस्वीकरण: मैंने अभी तक जावा 8 का उपयोग नहीं किया है, केवल इसके बारे में पढ़ें।

Function<String, Integer>फेंकता नहीं है IOException, इसलिए आप इसमें कोई कोड नहीं डाल सकते हैं throws IOException। यदि आप एक ऐसी विधि को कॉल कर रहे हैं, जो एक की अपेक्षा करती है Function<String, Integer>, तो उस पद्धति से गुजरने वाला लंबोदा फेंक नहीं सकता IOException, अवधि। आप या तो इस तरह एक लंबदा लिख ​​सकते हैं (मुझे लगता है कि यह लंबोदर सिंटैक्स है, निश्चित नहीं है):

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}

या, यदि आप जिस विधि से लैम्बडा पास कर रहे हैं, वह वही है जिसे आपने स्वयं लिखा है, तो आप एक नए कार्यात्मक इंटरफ़ेस को परिभाषित कर सकते हैं और इसके बजाय पैरामीटर प्रकार का उपयोग कर सकते हैं Function<String, Integer>:

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}

अपने इंटरफ़ेस से पहले @FunctionalInterface एनोटेशन जोड़ें, तभी यह लैम्ब्डा के लिए उपयोग करने योग्य होगा।
गंगनुस

13
@ गैंग्नस: लैम्बदास के @FunctionalInterfaceलिए प्रयोग करने योग्य होने के लिए एनोटेशन की आवश्यकता नहीं है। हालाँकि, यह पवित्रता जाँच के लिए अनुशंसित है।
तन्मय पाटिल

9

यदि आप किसी तीसरे पक्ष के परिवाद ( Vavr ) का उपयोग करने का मन नहीं बनाते हैं, जिसे आप लिख सकते हैं

CheckedFunction1<String, Integer> f = this::myMethod;

इसमें तथाकथित Try monad भी है जो त्रुटियों को संभालता है:

Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
        .map(i -> ...) // only executed on Success
        ...

कृपया यहाँ और पढ़ें ।

डिस्क्लेमर: मैं ववर का निर्माता हूं।


7

आप unthrow आवरण का उपयोग कर सकते हैं

Function<String, Integer> func1 = s -> Unthrow.wrap(() -> myMethod(s));

या

Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);

6

हालाँकि आप अपना खुद का कार्यात्मक इन्टरफेस बना सकते हैं जो नीचे दिया गया है।

@FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
  void accept(T instance) throws X;
}

फिर इसे नीचे दिए गए अनुसार लैंबडास या संदर्भों का उपयोग करके लागू करें।

import java.io.FileWriter;
import java.io.IOException;

//lambda expressions and the execute around method (EAM) pattern to
//manage resources

public class FileWriterEAM  {
  private final FileWriter writer;

  private FileWriterEAM(final String fileName) throws IOException {
    writer = new FileWriter(fileName);
  }
  private void close() throws IOException {
    System.out.println("close called automatically...");
    writer.close();
  }
  public void writeStuff(final String message) throws IOException {
    writer.write(message);
  }
  //...

  public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {

    final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
    try {
      block.accept(writerEAM);
    } finally {
      writerEAM.close();
    }
  }

  public static void main(final String[] args) throws IOException {

    FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));

    FileWriterEAM.use("eam2.txt", writerEAM -> {
        writerEAM.writeStuff("how");
        writerEAM.writeStuff("sweet");      
      });

    FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     

  }


 void writeIt() throws IOException{
     this.writeStuff("How ");
     this.writeStuff("sweet ");
     this.writeStuff("it is");

 }

}

6

आप ऐसा कर सकते हैं।

@Marcg का विस्तार करना UtilExceptionऔर <E extends Exception>जहाँ आवश्यक हो वहाँ जेनेरिक जोड़ना : कंपाइलर आपको फेंक क्लॉज़ और सब कुछ जोड़ने के लिए फिर से बाध्य करेगा जैसे कि आप जाव 8 की धाराओं पर मूल रूप से अपवादों की जाँच कर सकते हैं।

public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Function_WithExceptions<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    /**
     * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
     */
    public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E  {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }

}

public class LambdaExceptionUtilTest {

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao", "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    private static class MyTestException extends Exception { }
}

5

मैं एक लैम्बडा के अंदर Class.forName और Class.newInstance के साथ यह समस्या थी, इसलिए मैंने अभी किया:

public Object uncheckedNewInstanceForName (String name) {

    try {
        return Class.forName(name).newInstance();
    }
    catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

लैम्ब्डा के अंदर, Class.forName ("myClass") को कॉल करने के बजाय। newInstance () मुझे अभी अनचेक किया गया NewInstanceForName ("myClass")


4

फंक्शन रैपर का उपयोग करने का एक अन्य उपाय यह होगा कि या तो आपके परिणाम के रैपर का एक उदाहरण वापस किया जाए, सफ़लता का कहना है, अगर सब कुछ ठीक रहा, या तो इसका एक उदाहरण है, असफलता।

चीजों को स्पष्ट करने के लिए कुछ कोड:

public interface ThrowableFunction<A, B> {
    B apply(A a) throws Exception;
}

public abstract class Try<A> {

    public static boolean isSuccess(Try tryy) {
        return tryy instanceof Success;
    }

    public static <A, B> Function<A, Try<B>> tryOf(ThrowableFunction<A, B> function) {
        return a -> {
            try {
                B result = function.apply(a);
                return new Success<B>(result);
            } catch (Exception e) {
                return new Failure<>(e);
            }
        };
    }

    public abstract boolean isSuccess();

    public boolean isError() {
        return !isSuccess();
    }

    public abstract A getResult();

    public abstract Exception getError();
}

public class Success<A> extends Try<A> {

    private final A result;

    public Success(A result) {
        this.result = result;
    }

    @Override
    public boolean isSuccess() {
        return true;
    }

    @Override
    public A getResult() {
        return result;
    }

    @Override
    public Exception getError() {
        return new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object that) {
        if(!(that instanceof Success)) {
            return false;
        }
        return Objects.equal(result, ((Success) that).getResult());
    }
}

public class Failure<A> extends Try<A> {

    private final Exception exception;

    public Failure(Exception exception) {
        this.exception = exception;
    }

    @Override
    public boolean isSuccess() {
        return false;
    }

    @Override
    public A getResult() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Exception getError() {
        return exception;
    }
}

एक साधारण उपयोग मामला:

List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());

4

यह समस्या मुझे भी परेशान कर रही है; यही कारण है कि मैंने इस परियोजना को बनाया है ।

इसके साथ आप यह कर सकते हैं:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDK द्वारा परिभाषित 39 इंटरफेस का एक टोटला है जिसमें इस तरह के Throwingसमतुल्य हैं; उन सभी का @FunctionalInterfaceउपयोग धाराओं में किया जाता है (आधार Streamलेकिन यह भी IntStream, LongStreamऔरDoubleStream )।

और जैसा कि उनमें से प्रत्येक अपने गैर फेंकने वाले समकक्ष का विस्तार करते हैं, आप उन्हें सीधे लैम्ब्डा में भी उपयोग कर सकते हैं:

myStringStream.map(f) // <-- works

डिफ़ॉल्ट व्यवहार यह है कि जब आपका फेंका हुआ लैम्ब्डा एक चेक किया हुआ अपवाद फेंकता है, तो ए ThrownByLambdaExceptionकारण के रूप में चेक किए गए अपवाद के साथ फेंक दिया जाता है। आप इसलिए उस पर कब्जा कर सकते हैं और कारण प्राप्त कर सकते हैं।

अन्य सुविधाएँ भी उपलब्ध हैं।


मैं वास्तव में इस विचार को पसंद करता हूं, मेरी इच्छा है कि आप यहां दिए गए सुझाव के रूप में थ्रैबल्स को सामान्य बनाए: javaspecialists.eu/archive/Issue221.html , उदा: @FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }- इस तरह से उपयोगकर्ता को पकड़ने की आवश्यकता नहीं है Throwable, लेकिन इसके बजाय विशिष्ट चेक अपवाद।
ज़ोल्टन

@ ज़ोल्टन जो हर बार हालांकि हर बार अपवाद घोषित करने के लिए एक दर्द होगा; इसके अलावा, आप हमेशा .appApply () के बजाय .apply () का उपयोग कर सकते हैं, और पकड़ सकते हैं ThrownByLambdaException, आपके पास मूल अपवाद एक कारण के रूप में होगा (या आप उपयोग कर सकते हैं rethrow(...).as(MyRuntimeException.class))
fge

मुझे लगता है कि इस तरह का ( एक ) तरीका है
नेड ट्विग

@NedTwigg मैंने इसे बहुत पहले ही हल कर लिया है; मैं अब उपयोग कर सकता हूं Throwing.runnable()और अन्य, हमेशा क्षमताओं का
पीछा करते हुए

जंजीर की कार्यक्षमता बहुत अच्छी है! मेरी टिप्पणी इस बारे में थी कि क्या थ्रोइंगरुनबल में सामान्य अपवाद होना चाहिए या नहीं। ज़ोल्टन ने पूछा कि क्या आपके पुस्तकालय में जेनेरिक पैरामीटर के रूप में तर्क हो सकता है, और आपने कहा कि इसका उपयोग करने के लिए दर्द होगा। मेरा लिंक कोड की कुछ पंक्तियों के लिए था, जो अपवाद के रूप में सामान्य होने का एक तरीका बताते हैं, बिना दर्द के। जब तक मैं इसे गलत नहीं समझती, आपके पुस्तकालय में अपवाद सामान्य नहीं हैं (जो एक उचित डिजाइन विकल्प है, क्योंकि आप उन्हें सामान्य बनाकर बहुत अधिक उपयोगिता नहीं पाते हैं)।
नेड ट्विग

4

यहां पहले से ही बहुत सारी शानदार प्रतिक्रियाएं हैं। बस समस्या को एक अलग दृष्टिकोण से हल करने का प्रयास किया जा रहा है। इसके सिर्फ मेरे 2 सेंट, कृपया मुझे सही करें अगर मैं कहीं गलत हूं।

FunctionalInterface में थ्रो क्लॉज एक अच्छा विचार नहीं है

मुझे लगता है कि निम्न कारणों से फेंकता IOException लागू करना एक अच्छा विचार नहीं है

  • यह मुझे स्ट्रीम / लैम्ब्डा के प्रति-विरोधी पैटर्न जैसा लगता है। पूरा विचार यह है कि कॉलर यह तय करेगा कि किस कोड को प्रदान करना है और अपवाद को कैसे संभालना है। कई स्थितियों में, IOException क्लाइंट के लिए लागू नहीं हो सकता है। उदाहरण के लिए, यदि ग्राहक को वास्तविक I / O करने के बजाय कैश / मेमोरी से मूल्य मिल रहा है।

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

               acceptMyMethod(s -> {
                    try {
                        Integer i = doSomeOperation(s);
                        return i;
                    } catch (IOException e) {
                        // try catch block because of throws clause
                        // in functional method, even though doSomeOperation
                        // might not be throwing any exception at all.
                        e.printStackTrace();
                    }
                    return null;
                });

    बदसूरत यह नहीं है? इसके अलावा, जैसा कि मैंने अपने पहले बिंदु में उल्लेख किया है कि doSomeOperation पद्धति IOException (क्लाइंट / कॉलर के कार्यान्वयन के आधार पर) को फेंक नहीं सकती है या नहीं कर सकती है, लेकिन आपके फंक्शनल इंस्टीट्यूशन विधि में थ्रो क्लॉज के कारण, मुझे हमेशा लिखना होगा पकड़ने की कोशिश।

अगर मैं वास्तव में इस API को जानता हूँ तो IOException फेंकता है तो मैं क्या करूँ?

  • तब शायद हम कार्यात्मक इंटरफेस को भ्रमित कर रहे हैं ठेठ इंटरफेस के साथ। यदि आप जानते हैं कि यह एपीआई IOException को फेंक देगा, तो शायद आप कुछ डिफ़ॉल्ट / सार व्यवहार भी जानते हैं। मुझे लगता है कि आपको एक इंटरफ़ेस परिभाषित करना चाहिए और अपने पुस्तकालय (डिफ़ॉल्ट / अमूर्त कार्यान्वयन के साथ) को निम्नानुसार तैनात करना चाहिए

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    }

    लेकिन, क्लाइंट के लिए ट्राइ-कैच की समस्या अभी भी मौजूद है। यदि मैं स्ट्रीम में आपके एपीआई का उपयोग करता हूं, तो मुझे अभी भी छिपाने की कोशिश करने वाले ब्लॉक में IOException को संभालने की आवश्यकता है।

  • निम्नानुसार एक डिफ़ॉल्ट स्ट्रीम-फ्रेंडली एपीआई प्रदान करें

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    
        default Optional<Integer> myMethod(String s, Consumer<? super Exception> exceptionConsumer) {
            try {
                return Optional.ofNullable(this.myMethod(s));
            } catch (Exception e) {
                if (exceptionConsumer != null) {
                    exceptionConsumer.accept(e);
                } else {
                    e.printStackTrace();
                }
            }
    
            return Optional.empty();
        }
    }

    डिफ़ॉल्ट विधि उपभोक्ता वस्तु को तर्क के रूप में लेती है, जो अपवाद को संभालने के लिए जिम्मेदार होगी। अब, क्लाइंट के दृष्टिकोण से, कोड इस तरह दिखेगा

    strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
                    .filter(Optional::isPresent)
                    .map(Optional::get).collect(toList());

    अच्छा ठीक है? बेशक, लॉगर या अन्य हैंडलिंग लॉजिक का उपयोग अपवाद के बजाय किया जा सकता है :: PrintStackTrace।

  • आप https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptively-java.util.fil.Function- के समान तरीके को भी उजागर कर सकते हैं । मतलब कि आप किसी अन्य विधि को उजागर कर सकते हैं, जिसमें पिछले विधि कॉल से अपवाद होगा। नुकसान यह है कि अब आप अपने एपीआई को स्टेटफुल बना रहे हैं, जिसका मतलब है कि आपको थ्रेड-सेफ्टी को संभालने की जरूरत है और जो आखिरकार एक परफॉर्मेंस हिट बन जाएगा। हालांकि विचार करने के लिए सिर्फ एक विकल्प।


मैं सहमत हूं कि चेक किए गए अपवाद को एक अनियंत्रित अपवाद में परिवर्तित करना, या अपवाद को निगलना एक अच्छा विचार नहीं है क्योंकि यह जानने का कोई तरीका नहीं है कि Streamएक अपवाद को किस तत्व ने उठाया। इस प्रकार, मुझे अपवाद हैंडलर रखने और मान्य नहीं होने वाले परिणामों को फ़िल्टर करने का विचार पसंद है। ध्यान दें कि आपका MyAmazingAPI प्रभावी रूप से है FunctionalInterface(इसलिए आप @FunctionalInterface एनोटेशन जोड़ सकते हैं)। इसके अलावा आपके पास उपयोग करने के बजाय एक डिफ़ॉल्ट मान हो सकता है Optional.empty()
जूलियन क्रोनगै

4

चुपके से मुहावराCheckedException लैंबडा अभिव्यक्ति को दरकिनार करने में सक्षम बनाता है । क CheckedExceptionमें लपेटना RuntimeExceptionसख्त त्रुटि से निपटने के लिए अच्छा नहीं है।

इसका उपयोग Consumerजावा संग्रह में उपयोग किए जाने वाले फ़ंक्शन के रूप में किया जा सकता है ।

यहाँ जिब के उत्तर का एक सरल और बेहतर संस्करण है ।

import static Throwing.rethrow;

@Test
public void testRethrow() {
    thrown.expect(IOException.class);
    thrown.expectMessage("i=3");

    Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
        int i = e.intValue();
        if (i == 3) {
            throw new IOException("i=" + i);
        }
    }));
}

यह सिर्फ एक में लैम्ब्डा wrapps rethrow । यह आपके लैम्ब्डा में फेंकी गई CheckedExceptionकिसी भी चीज को पुनर्जीवित करता है Exception

public final class Throwing {
    private Throwing() {}

    @Nonnull
    public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
        return consumer;
    }

    /**
     * The compiler sees the signature with the throws T inferred to a RuntimeException type, so it
     * allows the unchecked exception to propagate.
     * 
     * http://www.baeldung.com/java-sneaky-throws
     */
    @SuppressWarnings("unchecked")
    @Nonnull
    public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
        throw (E) ex;
    }

}

एक पूर्ण कोड और इकाई परीक्षण यहां खोजें


3

इसके लिए आप ET का इस्तेमाल कर सकते हैं । ET अपवाद रूपांतरण / अनुवाद के लिए एक छोटा जावा 8 पुस्तकालय है।

ET के साथ ऐसा दिखता है:

// Do this once
ExceptionTranslator et = ET.newConfiguration().done();

...

// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslatorउदाहरण थ्रेड सुरक्षित हैं जो कई घटकों द्वारा साझा किए जा सकते हैं। FooCheckedException -> BarRuntimeExceptionयदि आप चाहें तो आप अधिक विशिष्ट अपवाद रूपांतरण नियमों (जैसे ) को कॉन्फ़िगर कर सकते हैं। यदि कोई अन्य नियम उपलब्ध नहीं हैं, तो चेक किए गए अपवाद स्वचालित रूप से परिवर्तित हो जाते हैं RuntimeException

(डिस्क्लेमर: मैं ईटी का लेखक हूं)


2
लगता है कि आप इस लाइब्रेरी के लेखक हैं। एसओ नियमों के अनुसार , आपको अपने उत्तरों में अपनी संबद्धता का खुलासा करना होगा । कृपया अपने उत्तर में स्पष्ट रूप से जोड़ें कि आपने यह पुस्तकालय (अन्य ईटी-संबंधित उत्तरों के लिए समान) लिखा है।
टैगिर वलेव

2
हाय टैगिर, संकेत के लिए धन्यवाद। मैंने जवाब अपडेट किया।
माइक

2

मैं जो कर रहा हूं वह अपवाद के मामले में उपयोगकर्ता को वह मूल्य देने की अनुमति देता है जो वह वास्तव में चाहता है। तो मैं कुछ इस तरह से देख रहा हूँ

public static <T, R> Function<? super T, ? extends R> defaultIfThrows(FunctionThatThrows<? super T, ? extends R> delegate, R defaultValue) {
    return x -> {
        try {
            return delegate.apply(x);
        } catch (Throwable throwable) {
            return defaultValue;
        }
    };
}

@FunctionalInterface
public interface FunctionThatThrows<T, R> {
    R apply(T t) throws Throwable;
}

और फिर इस तरह कॉल किया जा सकता है:

defaultIfThrows(child -> child.getID(), null)

1
यह इस विचार का एक विस्तार है जो "डिफ़ॉल्ट मान" रणनीति (जैसा कि आपके उत्तर में है), और "रीन्थ्रो रनटाइमएक्सैप्शन" रणनीति के बीच अंतर करता है, जहां एक डिफ़ॉल्ट मान आवश्यक नहीं है।
नेड ट्विग

2

यदि आप साइक्लॉप्स-रिएक्शन के साथ, किसी तीसरे पक्ष के पुस्तकालय का उपयोग करने में कोई आपत्ति नहीं करते हैं , तो एक पुस्तकालय जिसमें मैं योगदान देता हूं, आप लिखने के लिए FluentFunctions API का उपयोग कर सकते हैं

 Function<String, Integer> standardFn = FluentFunctions.ofChecked(this::myMethod);

-Checked एक jOOλ CheckedFunction लेता है और एक मानक (अनियंत्रित) JDK java.util.function.Function पर वापस भेजा गया संदर्भ देता है।

वैकल्पिक रूप से आप FluentFunctions एपीआई के माध्यम से कैप्चर किए गए फ़ंक्शन के साथ काम कर सकते हैं!

उदाहरण के लिए, अपने तरीके को निष्पादित करने के लिए, इसे 5 बार तक पुन: प्रयास करें और लॉग इन करने की स्थिति आप लिख सकते हैं

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");

2

डिफ़ॉल्ट रूप से, जावा 8 फ़ंक्शन अपवाद को फेंकने की अनुमति नहीं देता है और जैसा कि कई उत्तरों में सुझाव दिया गया है कि इसे प्राप्त करने के कई तरीके हैं, एक तरीका यह है:

@FunctionalInterface
public interface FunctionWithException<T, R, E extends Exception> {
    R apply(T t) throws E;
}

इस रूप में परिभाषित:

private FunctionWithException<String, Integer, IOException> myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};

और कॉलर विधि में एक ही अपवाद जोड़ें throwsया try/catch


2

एक कस्टम रिटर्न प्रकार बनाएं जो चेक किए गए अपवाद को प्रचारित करेगा। यह एक नया इंटरफ़ेस बनाने का एक विकल्प है जो कार्यात्मक इंटरफ़ेस की विधि पर "फेंकता अपवाद" के मामूली संशोधन के साथ मौजूदा कार्यात्मक इंटरफ़ेस को दर्पण करता है।

परिभाषा

CheckedValueSupplier

public static interface CheckedValueSupplier<V> {
    public V get () throws Exception;
}

CheckedValue

public class CheckedValue<V> {
    private final V v;
    private final Optional<Exception> opt;

    public Value (V v) {
        this.v = v;
    }

    public Value (Exception e) {
        this.opt = Optional.of(e);
    }

    public V get () throws Exception {
        if (opt.isPresent()) {
            throw opt.get();
        }
        return v;
    }

    public Optional<Exception> getException () {
        return opt;
    }

    public static <T> CheckedValue<T> returns (T t) {
        return new CheckedValue<T>(t);
    }

    public static <T> CheckedValue<T> rethrows (Exception e) {
        return new CheckedValue<T>(e);
    }

    public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            return Result.rethrows(e);
        }
    }

    public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

प्रयोग

//  Don't use this pattern with FileReader, it's meant to be an
//  example.  FileReader is a Closeable resource and as such should
//  be managed in a try-with-resources block or in another safe
//  manner that will make sure it is closed properly.

//  This will not compile as the FileReader constructor throws
//  an IOException.
    Function<String, FileReader> sToFr =
        (fn) -> new FileReader(Paths.get(fn).toFile());

// Alternative, this will compile.
    Function<String, CheckedValue<FileReader>> sToFr = (fn) -> {
        return CheckedValue.from (
            () -> new FileReader(Paths.get("/home/" + f).toFile()));
    };

// Single record usage
    // The call to get() will propagate the checked exception if it exists.
    FileReader readMe = pToFr.apply("/home/README").get();


// List of records usage
    List<String> paths = ...; //a list of paths to files
    Collection<CheckedValue<FileReader>> frs =
        paths.stream().map(pToFr).collect(Collectors.toList());

// Find out if creation of a file reader failed.
    boolean anyErrors = frs.stream()
        .filter(f -> f.getException().isPresent())
        .findAny().isPresent();

क्या चल रहा है?

एक एकल कार्यात्मक इंटरफ़ेस जो एक चेक किए गए अपवाद को फेंकता है ( CheckedValueSupplier)। यह एकमात्र कार्यात्मक इंटरफ़ेस होगा जो चेक किए गए अपवादों की अनुमति देता है। अन्य सभी कार्यात्मक इंटरफेस CheckedValueSupplierकिसी भी कोड को लपेटने का लाभ उठाएंगे जो एक चेक किए गए अपवाद को फेंकता है।

CheckedValueवर्ग किसी भी तर्क है कि एक जाँच अपवाद फेंकता को क्रियान्वित करने का परिणाम का आयोजन करेगा। यह जाँच किए गए अपवाद के प्रसार को रोकता है जब तक कि बिंदु उस कोड तक पहुंचने का प्रयास नहीं करता जिसमें मूल्य CheckedValueशामिल है।

इस दृष्टिकोण के साथ समस्याओं।

  • अब हम "अपवाद" फेंक रहे हैं जो मूल रूप से फेंके गए विशिष्ट प्रकार को प्रभावी ढंग से छिपा रहे हैं।
  • हम इस बात से अनजान हैं कि एक अपवाद तब तक CheckedValue#get()होता है जब तक कि उसे बुलाया नहीं जाता।

उपभोक्ता एट अल

कुछ कार्यात्मक इंटरफेस (Consumer उदाहरण के लिए) को एक अलग तरीके से संभाला जाना चाहिए क्योंकि वे एक वापसी मूल्य प्रदान नहीं करते हैं।

उपभोक्ता के बदले कार्य

एक दृष्टिकोण उपभोक्ता के बजाय एक फ़ंक्शन का उपयोग करना है, जो धाराओं को संभालते समय लागू होता है।

    List<String> lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
    .map(e -> CheckedValueSupplier.from(
        () -> {throwyMethod(e); return e;}))
    .filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior

आगे बढ़ाएं

वैकल्पिक रूप से, आप हमेशा ए तक बढ़ सकते हैं RuntimeException। ऐसे अन्य उत्तर हैं जो चेक किए गए अपवाद को बढ़ाते हैं Consumer

उपभोग मत करो।

बस सभी एक साथ कार्यात्मक इंटरफेस से बचें और लूप के लिए एक अच्छे-ओले-फ़ैशन का उपयोग करें।


2

मैं एक अतिभारित उपयोगिता फ़ंक्शन का उपयोग करता हूं, जिसे unchecked()कई उपयोग-मामलों को संभालता है।


कुछ नमूने का उपयोग करता है

unchecked(() -> new File("hello.txt").createNewFile());

boolean fileWasCreated = unchecked(() -> new File("hello.txt").createNewFile());

myFiles.forEach(unchecked(file -> new File(file.path).createNewFile()));

सहायक इकाइयों का समर्थन

public class UncheckedUtils {

    @FunctionalInterface
    public interface ThrowingConsumer<T> {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

    public static <T> Consumer<T> unchecked(
            ThrowingConsumer<T> throwingConsumer
    ) {
        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    public static <T> T unchecked(
            ThrowingSupplier<T> throwingSupplier
    ) {
        try {
            return throwingSupplier.get();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static void unchecked(
            ThrowingRunnable throwing
    ) {
        try {
            throwing.run();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

0

प्रस्तावित समाधानों में से कई अपवाद के प्रकार में पारित करने के लिए ई के एक सामान्य तर्क का उपयोग करते हैं जो फेंक दिया जाता है।

उस एक कदम को आगे बढ़ाएं, और अपवाद के प्रकार में जाने के बजाय, अपवाद के प्रकार के उपभोक्ता में पास करें, जैसा कि ...

Consumer<E extends Exception>

आप कई पुन: प्रयोज्य विविधताएं बना सकते हैं, Consumer<Exception>जो आपके आवेदन की सामान्य अपवाद हैंडलिंग आवश्यकताओं को कवर करेगी।


0

मैं कुछ सामान्य करूंगा:

public interface Lambda {

    @FunctionalInterface
    public interface CheckedFunction<T> {

        T get() throws Exception;
    }

    public static <T> T handle(CheckedFunction<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception exception) {
            throw new RuntimeException(exception);

        }
    }
}

उपयोग:

 Lambda.handle(() -> method());

0

का प्रयोग करें Jool Libraryया कहना jOOλ libraryसेJOOQ । यह न केवल अनियंत्रित अपवाद संभाले हुए इंटरफेस प्रदान करता है, बल्कि बहुत सारे उपयोगी तरीकों के साथ Seq वर्ग भी प्रदान करता है।

इसके अलावा, इसमें 16 मापदंडों के साथ कार्यात्मक इंटरफेस शामिल हैं। इसके अलावा, यह टपल क्लास प्रदान करता है जो विभिन्न परिदृश्यों में उपयोग किया जाता है।

जूल गिट लिंक

विशेष रूप से org.jooq.lambda.fi.util.functionपैकेज के लिए लाइब्रेरी लुकअप में । इसमें चेक-प्रीपेड के साथ जावा -8 से सभी इंटरफेस हैं। संदर्भ के लिए नीचे देखें: -

यहाँ छवि विवरण दर्ज करें


0

मैं कुछ जेनेरिक जादू के साथ एक छोटे से परिवाद का लेखक हूं, किसी भी जावा अपवाद को कहीं भी पकड़ने और उन्हें लपेटने की आवश्यकता के बिनाRuntimeException

उपयोग: unchecked(() -> methodThrowingCheckedException())

public class UncheckedExceptions {

    /**
     * throws {@code exception} as unchecked exception, without wrapping exception.
     *
     * @return will never return anything, return type is set to {@code exception} only to be able to write <code>throw unchecked(exception)</code>
     * @throws T {@code exception} as unchecked exception
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T unchecked(Exception exception) throws T {
        throw (T) exception;
    }


    @FunctionalInterface
    public interface UncheckedFunction<R> {
        R call() throws Exception;
    }

    /**
     * Executes given function,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @return result of function
     * @see #unchecked(Exception)
     */
    public static <R> R unchecked(UncheckedFunction<R> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }


    @FunctionalInterface
    public interface UncheckedMethod {
        void call() throws Exception;
    }

    /**
     * Executes given method,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @see #unchecked(Exception)
     */
    public static void unchecked(UncheckedMethod method) {
        try {
            method.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }
}

source: https://github.com/qoomon/unchecked-exception-java


-7
public void frankTest() {
    int pageId= -1;

    List<Book> users= null;
    try {
        //Does Not Compile:  Object page=DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> new Portal(rw.getInt("id"), "", users.parallelStream().filter(uu -> uu.getVbid() == rw.getString("user_id")).findFirst().get(), rw.getString("name")));

        //Compiles:
        Object page= DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> { 
            try {
                final Book bk= users.stream().filter(bp -> { 
                    String name= null;
                    try {
                        name = rw.getString("name");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return bp.getTitle().equals(name); 
                }).limit(1).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new Portal(rw.getInt("id"), "", users.get(0), rw.getString("name")); 
        } );
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

3
अपने काम पर मन लगाने के लिए? कोड-केवल उत्तर इतने उपयोगी नहीं हैं।
फैंटमैक्सएक्स

@Franky आप अपनी प्रस्तुति को 4 की जगह 4 का उपयोग करके ठीक कर सकते हैं <code>/<code>:)
AdrieanKhisbe
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.