Java 8:Lambda-Streams,按异常方法过滤 [英] Java 8: Lambda-Streams, Filter by Method with Exception

查看:28
本文介绍了Java 8:Lambda-Streams,按异常方法过滤的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在尝试 Java 8 的 Lambda 表达式时遇到问题.通常它工作正常,但现在我有抛出 IOException 的方法.最好看看下面的代码:

I have a problem trying out the Lambda expressions of Java 8. Usually it works fine, but now I have methods that throw IOException's. It's best if you look at the following code:

class Bank{
    ....
    public Set<String> getActiveAccountNumbers() throws IOException {
        Stream<Account> s =  accounts.values().stream();
        s = s.filter(a -> a.isActive());
        Stream<String> ss = s.map(a -> a.getNumber());
        return ss.collect(Collectors.toSet());
    }
    ....
}

interface Account{
    ....
    boolean isActive() throws IOException;
    String getNumber() throws IOException;
    ....
}

问题是,它无法编译,因为我必须捕获 isActive- 和 getNumber-Methods 的可能异常.但即使我明确使用如下所示的 try-catch-Block,它仍然无法编译,因为我没有捕获异常.所以要么JDK有bug,要么我不知道如何捕捉这些异常.

The problem is, it doesn't compile, because I have to catch the possible exceptions of the isActive- and the getNumber-Methods. But even if I explicitly use a try-catch-Block like below, it still doesn't compile because I don't catch the Exception. So either there is a bug in JDK, or I don't know how to catch these Exceptions.

class Bank{
    ....
    //Doesn't compile either
    public Set<String> getActiveAccountNumbers() throws IOException {
        try{
            Stream<Account> s =  accounts.values().stream();
            s = s.filter(a -> a.isActive());
            Stream<String> ss = s.map(a -> a.getNumber());
            return ss.collect(Collectors.toSet());
        }catch(IOException ex){
        }
    }
    ....
}

我怎样才能让它工作?有人可以提示我正确的解决方案吗?

How can I get it work? Can someone hint me to the right solution?

推荐答案

必须在异常在它转义 lambda 之前捕获:

You must catch the exception before it escapes the lambda:

s = s.filter(a -> {
    try {
        return a.isActive();
    } catch (IOException e) {
        throw new UncheckedIOException(e);
    }
});

请考虑这样一个事实,即 lambda 不是在您编写它的地方评估的,而是在 JDK 类中的某个完全不相关的地方评估的.所以这将是引发检查异常的地方,并且在那个地方它没有被声明.

Consider the fact that the lambda isn't evaluated at the place you write it, but at some completely unrelated place, within a JDK class. So that would be the point where that checked exception would be thrown, and at that place it isn't declared.

您可以使用 lambda 的包装器来处理它,该包装器将已检查的异常转换为未检查的异常:

You can deal with it by using a wrapper of your lambda that translates checked exceptions to unchecked ones:

public static <T> T uncheckCall(Callable<T> callable) {
    try {
        return callable.call();
    } catch (RuntimeException e) {
        throw e;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

你的例子可以写成

return s.filter(a -> uncheckCall(a::isActive))
        .map(Account::getNumber)
        .collect(toSet());


在我的项目中,我处理这个问题时不进行包装;相反,我使用一种有效地消除编译器检查异常的方法.不用说,这应该小心处理,项目中的每个人都必须知道,检查的异常可能会出现在未声明的地方.这是管道代码:


In my projects I deal with this issue without wrapping; instead I use a method which effectively defuses compiler's checking of exceptions. Needless to say, this should be handled with care and everybody on the project must be aware that a checked exception may appear where it is not declared. This is the plumbing code:

public static <T> T uncheckCall(Callable<T> callable) {
    try {
        return callable.call();
    } catch (Exception e) {
        return sneakyThrow(e);
    }
}

public static void uncheckRun(RunnableExc r) {
    try {
        r.run();
    } catch (Exception e) {
        sneakyThrow(e);
    }
}

public interface RunnableExc {
    void run() throws Exception;
}

@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
    throw (T) t;
}

你可以期望得到一个 IOException 扔在你的脸上,即使 collect 没有声明它.在大多数,但不是所有现实生活中,无论如何,您可能只想重新抛出异常,并将其作为一般故障处理.在所有这些情况下,清晰或正确不会丢失任何内容.请注意其他情况,您实际上希望在现场对异常做出反应.编译器不会让开发人员知道那里有一个 IOException 要捕获,如果你试图捕获它,编译器实际上会抱怨,因为我们已经欺骗它相信没有这样的异常可以被扔掉.

and you can expect to get an IOException thrown in your face, even though collect does not declare it. In most, but not all real-life cases you would want to just rethrow the exception, anyway, and handle it as a generic failure. In all those cases, nothing is lost in clarity or correctness. Just beware of those other cases, where you would actually want to react to the exception on the spot. The developer will not be made aware by the compiler that there is an IOException to catch there and the compiler will in fact complain if you try to catch it because we have fooled it into believing that no such exception can be thrown.

这篇关于Java 8:Lambda-Streams,按异常方法过滤的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆