当前位置: 首页 > 知识库问答 >
问题:

lambda中infinite while循环中的thread.sleep不需要'catch(InterruptedException)'-为什么不需要呢?

苏边浩
2023-03-14

我的问题是关于InterruptedException,它是从Thread.Sleep方法抛出的。在使用executorservice时,我注意到一些我不理解的奇怪行为;我的意思是:

ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(() -> {
        while(true)
        {
            //DO SOMETHING
            Thread.sleep(5000);
        }
    });

使用此代码,编译器不会给我任何错误或消息,即应该捕获来自Thread.SleepInterruptedException。但是当我试图改变循环条件并用下面这样的变量替换“true”时:

ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(() -> {
        while(tasksObserving)
        {
            //DO SOMETHING
            Thread.sleep(5000);
        }
    });

编译器不断抱怨必须处理interruptedexception。有人能给我解释一下为什么会发生这种情况,为什么如果条件设置为true,编译器会忽略InterruptedException?

共有1个答案

符献
2023-03-14

原因是这些调用实际上是对executorservice中可用的两个不同重载方法的调用;这些方法都采用不同类型的单个参数:

  1. 未来 提交(可调用 任务);
  2. 未来<?>提交(可运行任务);

然后,编译器将第一个问题中的lambda转换为可调用的<?>函数接口(调用第一个重载的方法);在第二种情况下,将lambda转换为runnable函数接口(因此调用第二个重载方法),因此需要处理抛出的exception;但在前面使用callable的情况下则不是这样。

    null

如果我们切换到将代码修剪成相关部分的示例(以便简单地研究奇怪的部分),那么我们可以编写与原始示例等价的代码:

    ExecutorService executor = Executors.newSingleThreadExecutor();

    // LAMBDA COMPILED INTO A 'Callable<?>'
    executor.submit(() -> {
        while (true)
            throw new Exception();
    });

    // LAMBDA COMPILED INTO A 'Runnable': EXCEPTIONS MUST BE HANDLED BY LAMBDA ITSELF!
    executor.submit(() -> {
        boolean value = true;
        while (value)
            throw new Exception();
    });

通过这些示例,可能更容易观察到第一个转换为可调用的<?>而第二个转换为可运行的的原因是编译器推断。

在这两种情况下,lambda主体都是void兼容的,因为块中的每个return语句都具有return;的形式。

现在,在第一种情况下,编译器执行以下操作:

  1. 检测到lambda中的所有执行路径都声明抛出检查异常(从现在起,我们将引用“exception”,仅表示“checked exceptions”)。这包括调用声明抛出异常的任何方法,以及显式调用抛出新的 ()
  2. 正确地得出结论:lambda的整个主体相当于声明抛出异常的代码块;当然必须执行以下操作:处理或重新抛出。
  3. 由于lambda不处理异常,因此编译器默认假定必须重新引发这些异常。
  4. 安全地推断此lambda必须匹配不能正常完成的功能接口,因此是值兼容的。
  5. 由于callable<?>runnable是此lambda的潜在匹配项,编译器选择最特定的匹配项(以覆盖所有方案);它是可调用的<?>,将lambda转换为它的实例,并创建对提交(可调用的<?>)重载方法的调用引用。
  1. 检测lambda中可能存在未声明抛出异常的执行路径(取决于待求值逻辑)。
  2. 由于不是所有的执行路径都声明抛出异常,编译器得出结论lambda的主体不一定等同于声明抛出异常的代码块--编译器并不关心/注意代码的某些部分是否声明它们可以,只有在整个主体是否声明时才会这样做。
  3. 安全地推断lambda不是值兼容的;因为它可以正常完成
  4. 选择Runnable(因为它是lambda要转换的唯一可用的拟合函数接口),并创建对submit(Runnable)重载方法的调用引用。所有这一切的代价是将处理任何异常的责任委托给用户,不管这些异常发生在lambda主体的各个部分中。

这是一个很好的问题-我有很多乐趣追下去,谢谢!

 类似资料:
  • 问题内容: 我的问题是关于,它是从方法中抛出的。在和我一起工作时,我注意到一些我不理解的怪异行为。这是我的意思: 有了这个代码,编译器不给我任何错误或消息从应该被抓。但是,当我尝试更改循环条件并用诸如此类的变量替换“ true”时: 编译器不断抱怨必须处理。有人可以向我解释为什么会发生这种情况,为什么将条件设置为true则编译器会忽略InterruptedException? 问题答案: 这样做的

  • 问题内容: 我正在用查询执行ajax请求,想知道为什么我的响应已经是JS对象。 如果我做一个 ‘obj’为null,但是我可以将’response’用作js对象数组。 这不是真正的问题,但是我想了解这种行为。 谢谢 问题答案: 当您进行AJAX调用并指定dataType JSON时,就会发生这种情况jQuery会在响应中为您调用jQuery.parseJSON。实际上,您可以根据数据类型指定要调用

  • 《铁锈之书》第3.5章摘录: 我们使用关键字和值。循环结束后,我们使用分号结束将值赋给的语句。 加上代码片段: 我理解这是如何工作的,以及为什么结果是20,但我注意到,如果我删除包含关键字的行上的分号,程序是等效的。 为什么分号在这种情况下是可选的?

  • 问题内容: 要编译此代码,我可以: 将我的通话置于try / catch块中,或 已经声明它可以抛出一个。 为什么我必须这样做? (示例代码来自Kathy Sierra的SCJP书 。) 我知道引发的异常是已检查的异常,因此我必须处理它,但是在什么情况下需要引发此异常? 问题答案: 如果以一种可以引发检查异常的方式声明方法(不是的子类),则调用该方法的代码必须在一个块中调用它,否则调用者方法必须声

  • 我一直在寻找答案,但我没有找到它,我需要在我继续我的测试之前弄明白。 我正在通过安装bash创建一个基于Alpine的映像,如下图所示: Hello.sh 我可以在不向docker-compose.yml添加的情况下访问,所以Alpine的映像中一定有我不理解和希望理解的东西。

  • 问题内容: 我对JAX-WS进行了概述,并注意到了(和)的一些引用。 在什么情况下需要?(我认为JSR 109服务器?!) 问题答案: 是使用SUN的参考实现将Web服务作为标准存档部署在非Java EE5 Servlet容器上时所需的专有部署描述符。 Sun的RI 用作servlet上下文事件的侦听器和调度程序servlet。两者都必须在中声明。然后需要该文件为定义Web服务端点,以使其知道必须