JDK 11编译失败,但JDK 8可以成功编译

6

该代码在JDK 8 (1.8.0_212)下编译正常,但使用JDK 11 (11.0.3),无论是Oracle JDK还是Open JDK (AWS Corretto),都编译失败。

尝试使用javac和Maven(maven版本3.6.1和maven-compiler-plugin版本3.8.0)进行编译,JDK 8可以编译成功,但JDK 11则无法编译。

import java.net.URL;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Stream;

public class AppDemo {
    public static void main(String[] args) {
        // NO error here
        giveMeStream("http://foo.com").map(wrap(url -> new URL(url)));

        List<String> list = new ArrayList<String>();
        list.add("http://foo.com/, http://bar.com/");
        // error: unreported exception MalformedURLException;
        // must be caught or declared to be thrown
        list.stream().flatMap(
            urls -> Arrays.<String>stream(urls.split(",")).map(wrap(url -> new URL(url)))
        );

        // error: unreported exception MalformedURLException;
        // must be caught or declared to be thrown
        Stream.concat(
            giveMeStream("http://foo.com").map(wrap(url -> new URL(url))),
            giveMeStream("http://bar.com").map(wrap(url -> new URL(url))));

    }


    static Stream<String> giveMeStream(String s) {
        return Arrays.stream(new String[]{s});
    }

    static <T, R, E extends Throwable> Function<T, R>
    wrap(FunException<T, R, E> fn) {
        return t -> {
            try {
                return fn.apply(t);
            } catch (Throwable throwable) {
                throw new RuntimeException(throwable);
            }
        };
    }

    interface FunException<T, R, E extends Throwable> {
        R apply(T t) throws E;
    }
}

错误:

Expected : No compilation error
Actual : compilation error for JDK11
Error message with JDK 11:

s.<String>stream(urls.split(",")).map(wrap(url -> new URL(url)))
                                                               ^
AppDemo.java:24: error: unreported exception MalformedURLException; must be caught or declared to be thrown
            giveMeStream("http://foo.com").map(wrap(url -> new URL(url))),
                                                           ^
AppDemo.java:25: error: unreported exception MalformedURLException; must be caught or declared to be thrown
            giveMeStream("http://bar.com").map(wrap(url -> new URL(url))));
                                                           ^
3 errors

6
你忘记包含实际的错误信息了吗? - Naman
嗨,我从错误的文件中发布了代码,我该如何更新代码? - Fazal
1
@Fazal 点击帖子底部的编辑按钮(在标签下方)。 - seenukarthi
@Karthikeyan Vaithilingam 谢谢,我已经编辑了代码,添加了编译错误。 - Fazal
2
似乎是类型推断问题。使用 (String url) -> new URL(url) 可以解决它。另外,你可以使用 Stream.of(s) 代替 Arrays.stream(new String[]{s}),这样就不需要 giveMeStream 方法了。所以你可以直接使用 Stream.of("http://foo.com", "http://bar.com").map(wrap(URL::new)) … - Holger
显示剩余2条评论
1个回答

2

可能是因为规范的轻微更新。这重要吗?这样做不会起作用。

在这里将抛出的异常转换为参数化类型没有真正的目的。此外,您将用这段代码创建相当长的RuntimeException链。请尝试使用以下代码代替:

static <T, R> Function<T, R> wrap(FunException<T, R> fn) {
    return t -> {
        try {
            return fn.apply(t);
        } catch (Error | RuntimeException ex) {
            throw ex;
        } catch (Throwable throwable) {
            throw new RuntimeException("Checked exception in lambda", throwable);
        }
    };
}

interface FunException<T, R> {
    R apply(T t) throws Throwable;
}

现在它会编译得很好。

给读者的提示:不要这样做。处理Java的规则(如已检查异常)的正确方法是应该去面对它们。使用hack来绕过语言的本质只会使您的代码非惯用语法(其他阅读您代码的人将无法理解,您也将很难读取其他人的代码。那是不好的),容易与其他库交互产生问题,而且各种旨在帮助的特性现在反而起了反作用(例如:在这里您会得到大量的根源异常链,这使得读取日志和异常跟踪比必要的更困难)。此外,走“小众路线”会导致有趣的时刻,例如以前可以编译的代码现在不再能编译。


1
这里是否有真正使用多个 catch 块的必要呢?Throwable 包装器总是会被调用!只是问一下。 - Kris
@rzwitserloot 感谢您的帮助。我完全同意处理已检查异常的建议。 - Fazal
我认为你可能没有理解@Fazal的观点。我们要求提供最小可重现示例,这正是Fazal给我们的。他不是在问如何做某事,而是在问为什么完全相同的代码在某些地方可以编译而在其他地方却不能。 - Simon G.
3
这个解决方案与UncheckedIOException一样地自然,后者是专门为了处理Stream API中的已检查的IOException而创建的,通过包装它来实现... - Holger
1
@Kris和Jean-Baptiste Yunes,当然这个额外的子句很有用:现在,任何可以直接抛出的异常都会被抛出。另一个将包装它们。通过足够多次的lambda应用,任何异常都将深入到RuntimeExceptions链的8层中。 - rzwitserloot
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接