मैं Java 8 स्ट्रीम के अंदर से CHECKED अपवाद कैसे फेंक सकता हूं?




lambda java-8 (12)

आप अनियंत्रित अपवादों को लपेटने के लिए एक आवरण विधि भी लिख सकते हैं, और यहां तक ​​कि एक और कार्यात्मक इंटरफ़ेस का प्रतिनिधित्व करने वाले अतिरिक्त पैरामीटर के साथ आवरण को बढ़ा सकते हैं (उसी रिटर्न प्रकार आर के साथ )। इस मामले में आप एक फ़ंक्शन पास कर सकते हैं जो अपवाद के मामले में निष्पादित और वापस आ जाएगा। नीचे उदाहरण देखें:

    @Test
    public void getClasses() {

        String[] classNames = {"java.lang.Object", "java.lang.Integer", "java.lang.Foo"};
        List<Class> classes =
                Stream.of(classNames)
                        .map(className -> {
                            try {
                                return Class.forName(className);
                            } catch (ClassNotFoundException e) {
                                // log the error
                                return null;
                            }
                        })
                        .filter(c -> c != null)
                        .collect(Collectors.toList());

        if (classes.size() != classNames.length) {
            // add your error handling here if needed or process only the resulting list
            System.out.println("Did not process all class names");
        }

        classes.forEach(System.out::println);
    }

मैं Java 8 स्ट्रीम / लैम्ब्डा के अंदर से CHECKED अपवाद कैसे फेंक सकता हूं?

दूसरे शब्दों में, मैं इस संकलन की तरह कोड बनाना चाहता हूं:

public List<Class> getClasses() throws ClassNotFoundException {     

    List<Class> classes = 
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
              .map(className -> Class.forName(className))
              .collect(Collectors.toList());                  
    return classes;
    }

यह कोड संकलित नहीं करता है, क्योंकि Class.forName() विधि फेंकता है ClassNotFoundException , जो कि जाँच की गई है।

कृपया ध्यान दें कि मैं एक रनटाइम अपवाद के अंदर चेक किए गए अपवाद को लपेटना नहीं चाहता हूं और इसके बजाय लिपटे अनियंत्रित अपवाद को फेंकना चाहता हूं। मैं जाँच किए गए अपवाद को स्वयं फेंकना चाहता हूं , और धारा में बदसूरत try / catches जोड़े बिना।


उन्नत समाधान के ऊपर टिप्पणियों को सारांशित करना एपीआई जैसे बिल्डर के साथ अनियंत्रित कार्यों के लिए एक विशेष आवरण का उपयोग करना है जो पुनर्प्राप्ति, पुनर्वसन और सप्रेसिंग प्रदान करता है।

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .map(Try.<String, Class<?>>safe(Class::forName)
                  .handle(System.out::println)
                  .unsafe())
          .collect(toList());

नीचे दिया गया कोड उपभोक्ता, आपूर्तिकर्ता और फ़ंक्शन इंटरफेस के लिए इसे प्रदर्शित करता है। इसका आसानी से विस्तार किया जा सकता है। इस उदाहरण के लिए कुछ सार्वजनिक कीवर्ड हटा दिए गए थे।

कक्षा का प्रयास करें ग्राहक कोड के लिए अंत बिंदु है। प्रत्येक फ़ंक्शन प्रकार के लिए सुरक्षित विधियों में अद्वितीय नाम हो सकता है। CheckedConsumer , CheckedSupplier और CheckedFunction lib कार्यों के अनुरूप जो स्वतंत्र रूप से इस्तेमाल किया जा सकता की जाँच कर रहे हैं की कोशिश करो

CheckedBuilder कुछ चेक किए गए फ़ंक्शन में अपवादों को संभालने के लिए इंटरफ़ेस है। अगर पिछले असफल रहा तो orTry दूसरे प्रकार के फ़ंक्शन को निष्पादित करने की अनुमति देता है। हैंडल अपवाद प्रकार फ़िल्टरिंग सहित अपवाद हैंडलिंग प्रदान करता है। हैंडलर का क्रम महत्वपूर्ण है। कम करें तरीकों असुरक्षित और rethrow निष्पादन श्रृंखला में rethrows पिछले अपवाद। तरीकों को कम orElse और orElseGet वैकल्पिक लोगों की तरह वैकल्पिक मान अगर सभी कार्यों में विफल रहा है। इसके अलावा विधि दमन है CheckedWrapper CheckedBuilder का सामान्य कार्यान्वयन है।

final class Try {

    public static <T> CheckedBuilder<Supplier<T>, CheckedSupplier<T>, T> 
        safe(CheckedSupplier<T> supplier) {
        return new CheckedWrapper<>(supplier, 
                (current, next, handler, orResult) -> () -> {
            try { return current.get(); } catch (Exception ex) {
                handler.accept(ex);
                return next.isPresent() ? next.get().get() : orResult.apply(ex);
            }
        });
    }

    public static <T> Supplier<T> unsafe(CheckedSupplier<T> supplier) {
        return supplier;
    }

    public static <T> CheckedBuilder<Consumer<T>, CheckedConsumer<T>, Void> 
        safe(CheckedConsumer<T> consumer) {
        return new CheckedWrapper<>(consumer, 
                (current, next, handler, orResult) -> t -> {
            try { current.accept(t); } catch (Exception ex) {
                handler.accept(ex);
                if (next.isPresent()) {
                    next.get().accept(t);
                } else {
                    orResult.apply(ex);
                }
            }
        });
    }

    public static <T> Consumer<T> unsafe(CheckedConsumer<T> consumer) {
        return consumer;
    }

    public static <T, R> CheckedBuilder<Function<T, R>, CheckedFunction<T, R>, R> 
        safe(CheckedFunction<T, R> function) {
        return new CheckedWrapper<>(function, 
                (current, next, handler, orResult) -> t -> {
            try { return current.applyUnsafe(t); } catch (Exception ex) {
                handler.accept(ex);
                return next.isPresent() ? next.get().apply(t) : orResult.apply(ex);
            }
        });
    }

    public static <T, R> Function<T, R> unsafe(CheckedFunction<T, R> function) {
        return function;
    }

    @SuppressWarnings ("unchecked")
    static <T, E extends Throwable> T throwAsUnchecked(Throwable exception) throws E { 
        throw (E) exception; 
    }
}

@FunctionalInterface interface CheckedConsumer<T> extends Consumer<T> {
    void acceptUnsafe(T t) throws Exception;
    @Override default void accept(T t) {
        try { acceptUnsafe(t); } catch (Exception ex) {
            Try.throwAsUnchecked(ex);
        }
    }
}

@FunctionalInterface interface CheckedFunction<T, R> extends Function<T, R> {
    R applyUnsafe(T t) throws Exception;
    @Override default R apply(T t) {
        try { return applyUnsafe(t); } catch (Exception ex) {
            return Try.throwAsUnchecked(ex);
        }
    }
}

@FunctionalInterface interface CheckedSupplier<T> extends Supplier<T> {
    T getUnsafe() throws Exception;
    @Override default T get() {
        try { return getUnsafe(); } catch (Exception ex) {
            return Try.throwAsUnchecked(ex);
        }
    }
}

interface ReduceFunction<TSafe, TUnsafe, R> {
    TSafe wrap(TUnsafe current, Optional<TSafe> next, 
            Consumer<Throwable> handler, Function<Throwable, R> orResult);
}

interface CheckedBuilder<TSafe, TUnsafe, R> {
    CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next);

    CheckedBuilder<TSafe, TUnsafe, R> handle(Consumer<Throwable> handler);

    <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handle(
            Class<E> exceptionType, Consumer<E> handler);

    CheckedBuilder<TSafe, TUnsafe, R> handleLast(Consumer<Throwable> handler);

    <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handleLast(
            Class<E> exceptionType, Consumer<? super E> handler);

    TSafe unsafe();
    TSafe rethrow(Function<Throwable, Exception> transformer);
    TSafe suppress();
    TSafe orElse(R value);
    TSafe orElseGet(Supplier<R> valueProvider);
}

final class CheckedWrapper<TSafe, TUnsafe, R> 
        implements CheckedBuilder<TSafe, TUnsafe, R> {

    private final TUnsafe function;
    private final ReduceFunction<TSafe, TUnsafe, R> reduceFunction;

    private final CheckedWrapper<TSafe, TUnsafe, R> root;
    private CheckedWrapper<TSafe, TUnsafe, R> next;

    private Consumer<Throwable> handlers = ex -> { };
    private Consumer<Throwable> lastHandlers = ex -> { };

    CheckedWrapper(TUnsafe function, 
            ReduceFunction<TSafe, TUnsafe, R> reduceFunction) {
        this.function = function;
        this.reduceFunction = reduceFunction;
        this.root = this;
    }

    private CheckedWrapper(TUnsafe function, 
            CheckedWrapper<TSafe, TUnsafe, R> prev) {
        this.function = function;
        this.reduceFunction = prev.reduceFunction;
        this.root = prev.root;
        prev.next = this;
    }

    @Override public CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next) {
        return new CheckedWrapper<>(next, this);
    }

    @Override public CheckedBuilder<TSafe, TUnsafe, R> handle(
            Consumer<Throwable> handler) {
        handlers = handlers.andThen(handler);
        return this;
    }

    @Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> 
        handle(Class<E> exceptionType, Consumer<E> handler) {
        handlers = handlers.andThen(ex -> {
            if (exceptionType.isInstance(ex)) {
                handler.accept(exceptionType.cast(ex));
            }
        });
        return this;
    }

    @Override public CheckedBuilder<TSafe, TUnsafe, R> handleLast(
            Consumer<Throwable> handler) {
        lastHandlers = lastHandlers.andThen(handler);
        return this;
    }

    @Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> 
        handleLast(Class<E> exceptionType, Consumer<? super E> handler) {
        lastHandlers = lastHandlers.andThen(ex -> {
            if (exceptionType.isInstance(ex)) {
                handler.accept(exceptionType.cast(ex));
            }
        });
        return this;
    }

    @Override public TSafe unsafe() {
        return root.reduce(ex -> Try.throwAsUnchecked(ex));
    }

    @Override
    public TSafe rethrow(Function<Throwable, Exception> transformer) {
        return root.reduce(ex -> Try.throwAsUnchecked(transformer.apply(ex)));
    }

    @Override public TSafe suppress() {
        return root.reduce(ex -> null);
    }

    @Override public TSafe orElse(R value) {
        return root.reduce(ex -> value);
    }

    @Override public TSafe orElseGet(Supplier<R> valueProvider) {
        Objects.requireNonNull(valueProvider);
        return root.reduce(ex -> valueProvider.get());
    }

    private TSafe reduce(Function<Throwable, R> orResult) {
        return reduceFunction.wrap(function, 
                Optional.ofNullable(next).map(p -> p.reduce(orResult)), 
                this::handle, orResult);
    }

    private void handle(Throwable ex) {
        for (CheckedWrapper<TSafe, TUnsafe, R> current = this; 
                current != null; 
                current = current.next) {
            current.handlers.accept(ex);
        }
        lastHandlers.accept(ex);
    }
}

मुझे लगता है कि यह दृष्टिकोण सही है:

public List<Class> getClasses() throws ClassNotFoundException {
    List<Class> classes;
    try {
        classes = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String").map(className -> {
            try {
                return Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new UndeclaredThrowableException(e);
            }
        }).collect(Collectors.toList());
    } catch (UndeclaredThrowableException e) {
        if (e.getCause() instanceof ClassNotFoundException) {
            throw (ClassNotFoundException) e.getCause();
        } else {
            // this should never happen
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
    return classes;
}

CallableUndeclaredThrowableException (जो कि इस अपवाद के लिए उपयोग का मामला है) के अंदर चेक किए गए अपवाद को लपेटकर और इसे बाहर कर देना।

हां, मुझे यह बदसूरत लगता है, और मैं इस मामले में लैम्ब्डा का उपयोग करने के खिलाफ सलाह दूंगा और बस एक अच्छे पुराने लूप में वापस आ जाऊंगा, जब तक कि आप एक समानांतर धारा के साथ काम नहीं कर रहे हैं और पार्लेलाइज़ेशन एक उद्देश्य लाभ लाता है जो कोड की अपठनीयता को सही ठहराता है।

जैसा कि कई अन्य लोगों ने बताया है, इस स्थिति के समाधान हैं, और मुझे आशा है कि उनमें से एक इसे जावा के भविष्य के संस्करण में बना देगा।


मैं इस तरह के रैपिंग अपवाद का उपयोग करता हूं:

public class CheckedExceptionWrapper extends RuntimeException {
    ...
    public <T extends Exception> CheckedExceptionWrapper rethrow() throws T {
        throw (T) getCause();
    }
}

इसे इन अपवादों को सांख्यिकीय रूप से संभालने की आवश्यकता होगी:

void method() throws IOException, ServletException {
    try { 
        list.stream().forEach(object -> {
            ...
            throw new CheckedExceptionWrapper(e);
            ...            
        });
    } catch (CheckedExceptionWrapper e){
        e.<IOException>rethrow();
        e.<ServletExcepion>rethrow();
    }
}

इसे ऑनलाइन आज़माएं!

हालांकि अपवाद को पहले rethrow() कॉल (ओह, जावा जेनरिक ...) के दौरान फिर से फेंक दिया जाएगा , इस तरह से संभावित अपवादों की एक सख्त सांख्यिकीय परिभाषा प्राप्त करने की अनुमति मिलती है (उन्हें घोषित करने की आवश्यकता होती है throws )। और न instanceof कुछ चाहिए।


यहाँ मूल समस्या के लिए एक अलग दृष्टिकोण या समाधान है। यहां मैं दिखाता हूं कि हमारे पास एक कोड लिखने का विकल्प है जो केवल अपवादों को पहचानने और हैंडल करने के लिए विकल्प के साथ मान्य मानों को संसाधित करेगा, जब अपवाद फेंक दिया गया था।

private void run() {
    List<String> list = Stream.of(1, 2, 3, 4).map(wrapper(i ->
            String.valueOf(++i / 0), i -> String.valueOf(++i))).collect(Collectors.toList());
    System.out.println(list.toString());
}

private <T, R, E extends Exception> Function<T, R> wrapper(ThrowingFunction<T, R, E> function, 
Function<T, R> onException) {
    return i -> {
        try {
            return function.apply(i);
        } catch (ArithmeticException e) {
            System.out.println("Exception: " + i);
            return onException.apply(i);
        } catch (Exception e) {
            System.out.println("Other: " + i);
            return onException.apply(i);
        }
    };
}

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

संभवतः, एक बेहतर और अधिक कार्यात्मक तरीका अपवादों को लपेटना और उन्हें धारा में आगे फैलाना है। पर एक नजर डालें Try के प्रकार Vavr उदाहरण के लिए।

उदाहरण:

interface CheckedFunction<I, O> {
    O apply(I i) throws Exception; }

static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
    return i -> {
        try {
            return f.apply(i);
        } catch(Exception ex) {

            throw new RuntimeException(ex);
        }
    } }

fileNamesToRead.map(unchecked(file -> Files.readAllLines(file)))

या

@SuppressWarnings("unchecked")
private static <T, E extends Exception> T throwUnchecked(Exception e) throws E {
    throw (E) e;
}

static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
    return arg -> {
        try {
            return f.apply(arg);
        } catch(Exception ex) {
            return throwUnchecked(ex);
        }
    };
}

2 कार्यान्वयन एक में अपवाद को लपेटने से बचा जाता है RuntimeExceptionthrowUnchecked काम करता है क्योंकि लगभग हमेशा सभी सामान्य अपवादों को जावा में अनियंत्रित माना जाता है।


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

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

निर्देश: बस अपने IDE में LambdaExceptionUtil को कॉपी / पेस्ट करें और फिर नीचे दिए गए LambdaExceptionUtilTest में दिखाए अनुसार इसका उपयोग करें।

public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Consumer_WithExceptions<T, E extends Exception> {
        void accept(T t) throws E;
    }

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

    /**
     * .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name))));
     */
    public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
        return t -> {
            try {
                consumer.accept(t);
            } catch (Exception exception) {
                throwActualException(exception);
            }
        };
    }

    /**
     * .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(expected = MyTestException.class)
    public void testConsumer() throws MyTestException {
        Stream.of((String)null).forEach(rethrowConsumer(s -> checkValue(s)));
    }

    private void checkValue(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
    }

    private class MyTestException extends Exception { }

    @Test
    public void testConsumerRaisingExceptionInTheMiddle() {
        MyLongAccumulator accumulator = new MyLongAccumulator();
        try {
            Stream.of(2L, 3L, 4L, null, 5L).forEach(rethrowConsumer(s -> accumulator.add(s)));
            fail();
        } catch (MyTestException e) {
            assertEquals(9L, accumulator.acc);
        }
    }

    private class MyLongAccumulator {
        private long acc = 0;
        public void add(Long value) throws MyTestException {
            if(value==null) {
                throw new MyTestException();
            }
            acc += value;
        }
    }

    @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();
    }

    @Test(expected = MyTestException.class)
    public void testFunctionRaisingException() throws MyTestException {
        Stream.of("ciao", null, "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
    }

}

आप नहीं कर सकते।

हालाँकि, आप throwing-lambdas पर throwing-lambdas नज़र डालना चाहते throwing-lambdas जो आपको इस तरह के "फेंकने वाले लंबोदा" को अधिक आसानी से हेरफेर करने की अनुमति देता है।

आपके मामले में, आप ऐसा कर पाएंगे:

import static com.github.fge.lambdas.functions.Functions.wrap;

final ThrowingFunction<String, Class<?>> f = wrap(Class::forName);

List<Class> classes =
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .map(f.orThrow(MyException.class))
          .collect(Collectors.toList());

और MyException को MyException

वह एक उदाहरण है। एक अन्य उदाहरण यह है कि आप .orReturn() कुछ डिफ़ॉल्ट मान सकते हैं।

ध्यान दें कि यह अभी भी एक कार्य प्रगति पर है, और अधिक आना है। बेहतर नाम, अधिक सुविधाएँ आदि।


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

आपका कोड बन जाएगा

public List<Class> getClasses() throws ClassNotFoundException {     
    Stream<String> classNames = 
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String");

    return ThrowingStream.of(classNames, ClassNotFoundException.class)
               .map(Class::forName)
               .collect(Collectors.toList());
}

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

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
      .map(rethrowFunction(Class::forName))
      .collect(Collectors.toList());

नोट Class::forName फेंकता है ClassNotFoundException , जिसकी जाँच की जाती है । स्ट्रीम स्वयं भी ClassNotFoundException फेंकता है, और कुछ अनियंत्रित अपवाद को लपेटता नहीं है।

public final class LambdaExceptionUtil {

@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
    void accept(T t) throws E;
    }

@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
    void accept(T t, U u) throws E;
    }

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

@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
    T get() throws E;
    }

@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
    void run() throws E;
    }

/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
    return t -> {
        try { consumer.accept(t); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
    return (t, u) -> {
        try { biConsumer.accept(t, u); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

/** .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) { throwAsUnchecked(exception); return null; }
        };
    }

/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
    return () -> {
        try { return function.get(); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
    {
    try { t.run(); }
    catch (Exception exception) { throwAsUnchecked(exception); }
    }

/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
    {
    try { return supplier.get(); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
    try { return function.apply(t); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

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

}

इसका उपयोग करने के तरीके के बारे में कई अन्य उदाहरण ( LambdaExceptionUtil रूप से LambdaExceptionUtil आयात करने के बाद):

@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));

    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(System.out::println));
    }

@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
    List<Class> classes1
          = Stream.of("Object", "Integer", "String")
                  .map(rethrowFunction(className -> Class.forName("java.lang." + className)))
                  .collect(Collectors.toList());

    List<Class> classes2
          = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                  .map(rethrowFunction(Class::forName))
                  .collect(Collectors.toList());
    }

@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
    Collector.of(
          rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
          StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
    }

@Test    
public void test_uncheck_exception_thrown_by_method() {
    Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));

    Class clazz2 = uncheck(Class::forName, "java.lang.String");
    }

@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
    Class clazz3 = uncheck(Class::forName, "INVALID");
    }    

नोट 1: ऊपर दिए गए LambdaExceptionUtil क्लास के rethrow तरीके बिना किसी डर के इस्तेमाल किए जा सकते हैं, और किसी भी स्थिति में उपयोग करने के लिए ठीक हैं। उपयोगकर्ता @PaoloC के लिए एक बड़ा धन्यवाद जिसने अंतिम समस्या को हल करने में मदद की: अब कंपाइलर आपको थ्रो क्लॉज़ और सब कुछ जोड़ने के लिए कहेंगे जैसे कि आप जावा 8 स्ट्रीम पर मूल रूप से चेक अपवाद फेंक सकते हैं।

नोट 2: ऊपर दिए गए LambdaExceptionUtil वर्ग के uncheck तरीके बोनस विधियां हैं, और यदि आप उनका उपयोग नहीं करना चाहते हैं तो उन्हें कक्षा से सुरक्षित रूप से हटाया जा सकता है। यदि आप उनका उपयोग करते हैं, तो इसे सावधानी से करें, और निम्नलिखित उपयोग के मामलों, फायदे / नुकसान और सीमाओं को समझने से पहले न करें:

• आप uncheck विधियों का उपयोग कर सकते हैं यदि आप एक ऐसी विधि कह रहे हैं जो शाब्दिक रूप से उस अपवाद को नहीं फेंक सकती है जो वह घोषित करता है। उदाहरण के लिए: नया स्ट्रिंग (बाइटएयर, "यूटीएफ -8") अनएवरेडएन्कोडिंग एक्ससेप्शन फेंकता है, लेकिन यूटीएफ -8 की गारंटी जावा स्पेक द्वारा हमेशा मौजूद रहने के लिए दी जाती है। यहाँ, थ्रो डिक्लेरेशन एक उपद्रव है और इसे कम से कम बॉयलरप्लेट से चुप करने का कोई भी उपाय स्वागत योग्य है: String text = uncheck(() -> new String(byteArr, "UTF-8"));

• यदि आप एक सख्त इंटरफ़ेस लागू कर रहे हैं तो आप uncheck विधियों का उपयोग कर सकते हैं, जहाँ आपके पास फेंकता घोषणा को जोड़ने का विकल्प नहीं है, और फिर भी एक अपवाद को फेंकना पूरी तरह से उचित है। केवल एक अपवाद को लपेटने का विशेषाधिकार प्राप्त करने के लिए इसे एक अपवाद के रूप में प्राप्त करने के लिए, एक अपवाद के साथ एक शानदार परिणाम प्राप्त होता है, जो वास्तव में गलत होने के बारे में कोई जानकारी नहीं देता है। एक अच्छा उदाहरण Runnable.run () है, जो किसी भी चेक किए गए अपवादों को नहीं फेंकता है।

• किसी भी मामले में, यदि आप uncheck विधियों का उपयोग करने का निर्णय लेते हैं, तो थ्रो क्लॉज के बिना CHECKED अपवादों को फेंकने के इन 2 परिणामों से अवगत रहें: 1) कॉलिंग-कोड इसे नाम से पकड़ने में सक्षम नहीं होगा (यदि आप कोशिश करते हैं) संकलक कहेंगे: अपवाद को कभी भी इसी तरह के बयान के शरीर में नहीं फेंका जाता है)। यह बुलबुला होगा और संभवत: कुछ "कैच एक्सेप्शन" या "थ्रोएबल" को पकड़कर मुख्य प्रोग्राम लूप में पकड़ा जाएगा, जो कि वैसे भी हो सकता है। 2) यह कम से कम आश्चर्य के सिद्धांत का उल्लंघन करता है: सभी संभावित अपवादों को पकड़ने की गारंटी देने में सक्षम होने के लिए यह RuntimeException को पकड़ने के लिए पर्याप्त नहीं होगा। इस कारण से, मेरा मानना ​​है कि इसे फ्रेमवर्क कोड में नहीं किया जाना चाहिए, बल्कि केवल व्यावसायिक कोड में जिसे आप पूरी तरह से नियंत्रित करते हैं।


TL; DR बस लोम्बोक का उपयोग करें @SneakyThrows

ईसाई हुजेर ने पहले से ही विस्तार से बताया है कि चेक अपवादों को एक धारा से क्यों फेंकना है, कड़ाई से बोलना, जावा की सीमाओं के कारण संभव नहीं है।

कुछ अन्य उत्तरों ने भाषा की सीमाओं के आस-पास आने के लिए ट्रिक्स बताई हैं, लेकिन फिर भी "चेक किए गए अपवाद को फेंकने की आवश्यकता को पूरा करने में सक्षम होने के साथ-साथ , और बिना बदसूरत कोशिश / स्ट्रीम में शामिल हुए" , उनमें से कुछ को अतिरिक्त लाइनों के दसियों की आवश्यकता होती है। बॉयलरप्लेट का।

मैं ऐसा करने के लिए एक और विकल्प पर प्रकाश डालने जा रहा हूं कि आईएमएचओ अन्य सभी की तुलना में बहुत साफ है: लोम्बोक का @SneakyThrows । यह अन्य उत्तरों से गुजरने में उल्लेख किया गया है, लेकिन बहुत सारे अनावश्यक विवरण के तहत थोड़ा सा दफन किया गया था।

परिणामी कोड उतना ही सरल है:

public List<Class> getClasses() throws ClassNotFoundException {
    List<Class> classes =
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                .map(className -> getClass(className))
                .collect(Collectors.toList());
    return classes;
}

@SneakyThrows                                 // <= this is the only new code
private Class<?> getClass(String className) {
    return Class.forName(className);
}

हमें सिर्फ एक Extract Method रिफैक्टरिंग (आईडीई द्वारा किया गया) और एक अतिरिक्त लाइन की आवश्यकता थी @SneakyThrows । एनोटेशन यह सुनिश्चित करने के लिए सभी बॉयलरप्लेट को जोड़ने का ख्याल रखता है कि आप अपने चेक किए गए अपवाद को बिना लपेटे RuntimeException और बिना स्पष्ट रूप से घोषित किए बिना फेंक सकते हैं ।


आपके प्रश्न का सरल उत्तर है: आप कम से कम सीधे नहीं कर सकते। और यह आपकी गलती नहीं है। ओरेकल ने इसे गड़बड़ कर दिया। वे जाँच किए गए अपवादों की अवधारणा पर चिपके रहते हैं, लेकिन असंगत तरीके से कार्यात्मक अपवादों, धाराओं, लंबोदर आदि को डिज़ाइन करते समय जाँच किए गए अपवादों का ध्यान रखना भूल गए हैं। यह सब रॉबर्ट सी। मार्टिन जैसे विशेषज्ञों की चक्की के लिए है, जो अपवादों को एक असफल प्रयोग कहते हैं।

मेरी राय में, यह एपीआई में एक विशाल बग और भाषा विनिर्देश में एक मामूली बग है।

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

भाषा विनिर्देश में बग यह है कि यह एक प्रकार के पैरामीटर को एक प्रकार के बजाय एक प्रकार की सूची को अनुमान लगाने की अनुमति नहीं देता है जब तक कि प्रकार पैरामीटर केवल उन स्थितियों में उपयोग किया जाता है जहां प्रकारों की एक सूची अनुमेय है ( throws क्लॉज)।

जावा प्रोग्रामर के रूप में हमारी अपेक्षा यह है कि निम्नलिखित कोड संकलित करें:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class CheckedStream {
    // List variant to demonstrate what we actually had before refactoring.
    public List<Class> getClasses(final List<String> names) throws ClassNotFoundException {
        final List<Class> classes = new ArrayList<>();
        for (final String name : names)
            classes.add(Class.forName(name));
        return classes;
    }

    // The Stream function which we want to compile.
    public Stream<Class> getClasses(final Stream<String> names) throws ClassNotFoundException {
        return names.map(Class::forName);
    }
}

हालाँकि, यह देता है:

[email protected]:~/playground/Java/checkedStream$ javac CheckedStream.java 
CheckedStream.java:13: error: incompatible thrown types ClassNotFoundException in method reference
        return names.map(Class::forName);
                         ^
1 error

जिस तरह से कार्यात्मक इंटरफेस को परिभाषित किया गया है वह वर्तमान में कंपाइलर को अपवाद को आगे Stream.map() से रोकता है - कोई घोषणा नहीं है जो Stream.map() को बताएगा कि यदि Function.apply() throws E , Stream.map() throws E

क्या गायब है, चेक किए गए अपवादों से गुजरने के लिए एक प्रकार के पैरामीटर की घोषणा है। निम्न कोड दिखाता है कि इस तरह के पास-थ्रू टाइप पैरामीटर वास्तव में वर्तमान सिंटैक्स के साथ कैसे घोषित किए जा सकते हैं। चिह्नित लाइन में विशेष मामले को छोड़कर, जो नीचे चर्चा की गई सीमा है, यह कोड उम्मीद के मुताबिक संकलन और व्यवहार करता है।

import java.io.IOException;
interface Function<T, R, E extends Throwable> {
    // Declare you throw E, whatever that is.
    R apply(T t) throws E;
}   

interface Stream<T> {
    // Pass through E, whatever mapper defined for E.
    <R, E extends Throwable> Stream<R> map(Function<? super T, ? extends R, E> mapper) throws E;
}   

class Main {
    public static void main(final String... args) throws ClassNotFoundException {
        final Stream<String> s = null;

        // Works: E is ClassNotFoundException.
        s.map(Class::forName);

        // Works: E is RuntimeException (probably).
        s.map(Main::convertClass);

        // Works: E is ClassNotFoundException.
        s.map(Main::throwSome);

        // Doesn't work: E is Exception.
        s.map(Main::throwSomeMore);  // error: unreported exception Exception; must be caught or declared to be thrown
    }   

    public static Class convertClass(final String s) {
        return Main.class;
    }   

    static class FooException extends ClassNotFoundException {}

    static class BarException extends ClassNotFoundException {}

    public static Class throwSome(final String s) throws FooException, BarException {
        throw new FooException();
    }   

    public static Class throwSomeMore(final String s) throws ClassNotFoundException, IOException  {
        throw new FooException();
    }   
}   

throwSomeMore के मामले में हम IOException को मिस होते हुए देखना IOException , लेकिन यह वास्तव में Exception याद करता है।

यह सही नहीं है क्योंकि प्रकार का अनुमान अपवाद के मामले में भी एकल प्रकार की तलाश में लगता है। क्योंकि प्रकार के अनुमान के लिए एकल प्रकार की आवश्यकता होती है, E को ClassNotFoundException और IOException एक सामान्य super को हल करने की आवश्यकता IOException , जो Exception

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

बुरी खबर यह है कि इसका मतलब है कि ओरेकल ने इसे गड़बड़ कर दिया। निश्चित रूप से वे उपयोगकर्ता-भूमि कोड को नहीं तोड़ेंगे, लेकिन मौजूदा कार्यात्मक इंटरफेस के अपवाद प्रकार के मापदंडों को पेश करने से सभी उपयोगकर्ता-भूमि कोड का संकलन टूट जाएगा जो इन इंटरफेस का स्पष्ट रूप से उपयोग करता है। उन्हें इसे ठीक करने के लिए कुछ नए सिंटेक्स शुगर का आविष्कार करना होगा।

इससे भी बुरी खबर यह है कि इस विषय पर पहले ही 2010 में ब्रायन गोएट्ज ने https://blogs.oracle.com/briangoetz/entry/exception_transparency_in_java (नया लिंक: http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001484.html पर चर्चा की थी। http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001484.html ) लेकिन मुझे सूचित किया गया है कि यह जांच अंततः सामने नहीं आई है, और यह कि ओरेकल में कोई वर्तमान कार्य नहीं है, जिसे मैं चेक किए गए अपवादों और लंबोदा के बीच की बातचीत को कम करने के लिए जानता हूं।






checked-exceptions