What is the difference between these constructs such that one won't compile?

感情迁移 提交于 2019-12-08 04:26:06

问题


A little backstory (ok, a lot): I've been working on creating classes that take java.util.function types and wrap their execution with try/catch blocks to remove the need for using try/catch from within lambda statements. Something that would allow this test code:

list.forEach(ExceptionWrapper.wrapConsumer(s -> {throw new Exception(s);}));

In doing so, I came up with this. It did not work.

public class ExceptionWrapper {
    public static <T> Consumer<T> wrapConsumer(Consumer<T> consumer){
        return t -> {
            try {
                consumer.accept(t);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
    }
}

Many incantations always result in

Error:(54, 61) java: unreported exception java.lang.Exception; must be caught or declared to be thrown

After much searching, I came across the jOOλ code. It looked nearly the same except they use an intermediary lambda construct that mimics the wrapped types but declares to throw an exception. I made my own (did NOT copy the code, just the concept) and it works pretty awesome

public interface ConsumerWrapper<T>{
    void accept(T t) throws Exception;
}

and making the change in ExceptionWrapper

    public static <T> Consumer<T> wrapConsumer(ConsumerWrapper<T> consumer){
        ...                                        //  ^ note change
    }

allows the initial test code to compile and run.

public static void main(String[] args) {
    List<String> strings = Arrays.asList("1");
    strings.forEach(System.out::println);
    strings.forEach(ExceptionWrapper.wrapConsumer(s -> {throw new Exception(s);}));
}
Exception in thread "main" java.lang.RuntimeException: java.lang.Exception: 1
    at crap.unk.ExceptionWrapper.lambda$wrapConsumer$2(ExceptionWrapper.java:39)
    at crap.unk.ExceptionWrapper$$Lambda$3/1401420256.accept(Unknown Source)
...
Caused by: java.lang.Exception: 1
    at crap.unk.ExceptionWrapper.lambda$main$3(ExceptionWrapper.java:54)
    at crap.unk.ExceptionWrapper$$Lambda$2/501263526.accept(Unknown Source)

THE QUESTION

Why wouldn't my original attempt work? Why does the use of the intermediary, that has the identical structure, make it work? It seems caused by the difference in the throws clause but I don't see why. Why is it different than passing an Object off to a method and surrounding a call with a try/catch?

回答1:


Your initial attempt at wrapConsumer didn't work because it still took a Consumer as a parameter, and your lambda expression that you attempted to wrap still threw an Exception -- a checked exception. Your try/catch is too far from the thrown exception, because at the point you create a lambda expression, you've created a Consumer there, and Consumer's accept method isn't declared to throw any checked exceptions.

The change to accepting a ConsumerWrapper works because that interface's method declaration allows it to throw Exception, with throws Exception. That allows you to create a lambda expression that throws a checked exception.



来源:https://stackoverflow.com/questions/30675052/what-is-the-difference-between-these-constructs-such-that-one-wont-compile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!