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

查看:20
本文介绍了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天全站免登陆