为什么不能在Java 8流中抛出异常?

4

E.g:

Person result = persons.stream()
                  .filter(x -> {
                    if ("test".equals(x.getName() ) ) {
                      throw new IOException("not possible inside stream y ?"); //any checked exception
                    }
                    //code here
                  })

我正在寻找原因,为什么即使声明代码的方法抛出IOException,它也不被允许?

2
你遇到了什么错误?可能是缺少return语句吗?我认为这应该是可能的。 - keuleJ
1
Lambda表达式必须返回一个布尔值。除此之外,你做得很好。 - sparc_spread
抱歉,我更新了我的问题。即使在方法签名中声明为throws或整个表达式在try/catch下,我仍无法抛出已检查的异常...寻找原因?或者是否有其他方法可以实现? - Om.
1
可能是如何在Java 8流中抛出已检查异常?的重复问题。 - fps
感谢@Federico。所以这是一个bug。 - Om.
2个回答

6

你的代码运行得非常完美,除了在throw new ...这一行末尾缺少分号,以及可能隐藏在// code here中的缺少返回语句。

你不能抛出一个已检查异常(RuntimeException 不是),因为已检查异常是方法签名的一部分,而 Predicate.test 方法没有声明它。

编辑: 为了更精确地了解发生了什么,以及为什么你不能在此处抛出已检查的异常,以下是你可以不使用 lambda 编写代码的方式:

从这个开始:

public Person myMethod() throws IOException {
    Person result = persons.stream()
              .filter(x -> {
                if ("test".equals(x.getName() ) ) {
                  throw new IOException("not possible inside stream y ?"); //any checked exception
                }
                //code here
                return true;
              });
    return person;
}

转化为:

public Person myMethod() throws IOException {
    Person result = persons.stream()
              .filter(new Predicate<Person>() {
                  public boolean test(Person x) {
                      if ("test".equals(x.getName() ) ) {
                          throw new IOException("not possible inside stream y ?"); //any checked exception
                      }
                      //code here
                      return true;
                  }
              });
    return person;
}

正如您所看到的,lambda表达式内部的代码现在位于匿名的Predicate类的test方法中,该类不声明任何已检查的异常。
为什么使用Predicate?因为它是filter方法期望的类型,而您可以使用lambda代替传统对象,因为它是一个单方法接口:只有test是抽象的,您的lambda签名应该与Predicate.test方法相同。
如果您真的希望能够处理已检查的异常,则链接的帖子(来自Frederico的评论)展示了一些绕过这些限制的方法。

抱歉,我更新了我的问题。即使在方法签名中声明为throws或整个表达式在try/catch下,我仍无法抛出已检查的异常...寻找原因?或者是否有其他方法可以实现? - Om.
我不会说 lambda 表达式在 test 方法内部 - 这太具有误导性了。Lambda 表达式在 myMethod 内部,但它必须满足 test 方法的签名约束。 - Holger
@Holger:我不是指lambda表达式,而是lambda内部的代码。我会编辑以澄清这一点。 - Thierry
我知道你的意思,但是lambda表达式的代码不在“test”方法内部;在“test”方法内部的代码可以访问“Predicate”接口的继承成员,并且在“test”方法内部,“this”指的是“Predicate”实例。这些都不适用于lambda表达式的代码,它无法访问“Predicate”成员,而“this”指的是“myMethod()”的所有者。此外,可访问性规则也不同。与“test”方法的唯一关系是满足其签名合同的要求。 - Holger
关于无障碍规则的好处。我会进一步编辑以删除错误的部分。 - Thierry

5
寻找不被允许的原因?
您正在实现一个没有声明已检查异常的Predicate
异常是副作用,不受函数式设计师的欢迎,很可能这就是它们得不到很好支持的原因。
我使用一个技巧将检查异常传递出去并稍后捕获它。另一个选择是使用未经检查的异常包装它或使用像IORuntimeException这样的类。在不同的情况下,我使用三个选项。 https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html

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