当前位置: 首页 > 面试题库 >

Lambda中的无限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);
        }
    });

有了这个代码,编译器不给我任何错误或消息InterruptedExceptionThread.sleep应该被抓。但是,当我尝试更改循环条件并用诸如此类的变量替换“
true”时:

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

编译器不断抱怨InterruptedException必须处理。有人可以向我解释为什么会发生这种情况,为什么将条件设置为true则编译器会忽略InterruptedException?


问题答案:

这样做的原因是,这些调用实际上是对ExecutorService;中可用的两种不同的重载方法的调用。这些方法中的每一个均采用不同类型的单个参数:

  1. <T> Future<T> submit(Callable<T> task);
  2. Future<?> submit(Runnable task);

然后发生的事情是,编译器正在将问题的第一种情况下的lambda转换为Callable<?>功能接口(调用第一个重载方法)。在第二个问题中,您将lambda转换为Runnable功能接口(因此调用了第二个重载方法),因此需要处理该Exception抛出的异常;但在以前的情况下不使用Callable

尽管两个功能接口均不接受任何参数,但Callable<?> 返回

  1. 可致电: V call() throws Exception;
  2. 可运行的: public abstract void run();

如果我们切换到将代码修整到相关部分的示例(以便轻松地研究好奇的位),那么我们可以编写与原始示例等效的代码:

    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();
    });

通过这些示例,可能更容易观察到第一个被转换为a Callable<?>,而第二个被转换为a Runnable的原因是由于 编译器推断

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

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

  1. 检测到lambda中的所有执行路径都声明抛出检查过的异常(从现在开始,我们将其称为 “ exception” ,仅表示 “ checked exceptions” )。这包括调用任何声明抛出异常的方法以及对的显式调用throw new <CHECKED_EXCEPTION>()
  2. 正确的结论是, WHOLE 拉姆达的身体相当于代码声明抛出异常块; 当然 必须 :处理或重新抛出。
  3. 由于lambda不会处理该异常,因此编译器默认情况下假定必须重新抛出这些异常。
  4. 安全地推断此lambda必须与功能接口匹配complete normally,因此是值兼容的。
  5. 由于Callable<?>Runnable是该lambda的潜在匹配项,因此编译器会选择最具体的匹配项(以涵盖所有方案);这是Callable<?>,将lambda转换为其实例,并创建对submit(Callable<?>)重载方法的调用引用。

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

  1. 检测lambda中可能存在 声明抛出异常的执行路径(取决于 要评估的逻辑 )。
  2. 由于不是所有的执行路径声明抛出异常,编译器的结论是,拉姆达的身体是 不是必然 等同于代码声明抛出异常块-编译不在乎/注意,如果代码的某些部分做宣布,他们可能,只有整个身体都可以。
  3. 安全地推断出lambda不兼容价值;自 五月 以来complete normally
  4. 选择Runnable(因为它是要转换为lambda 的唯一可用的 拟合 功能接口),并创建对submit(Runnable)重载方法的调用引用。所有这些都是以委托给用户为代价的,即有责任处理 可能* 在lambda主体部分中发生的任何Exception地方所引发的所有问题。 *

这是一个很好的问题-追逐它让我很开心,谢谢!



 类似资料:
  • 我的问题是关于,它是从方法抛出的。在使用时,我注意到一些我不理解的奇怪行为;我的意思是: 使用此代码,编译器不会给我任何错误或消息,即应该捕获来自的。但是当我试图改变循环条件并用下面这样的变量替换“true”时: 编译器不断抱怨必须处理。有人能给我解释一下为什么会发生这种情况,为什么如果条件设置为true,编译器会忽略InterruptedException?

  • 我有一个看起来很简单的问题,但由于某种原因我无法绕过它。基本上我的程序正在导致一个无限循环,我不知道为什么。 下面是我陷入的特定循环: 当我运行它时,它总是问我输入列#。我给它一个数字,它接受这个数字,$response变为True,但while循环继续运行,就好像<code>的$response</code>为false一样。我是Perl新手,所以可能我遗漏了一些东西,但是($response=

  • 尝试编写一个程序,其中用户输入他们一周的费用。麻烦在于我希望程序重新询问用户是否输入了不可接受的输入。我想出了如何检测负值的方法,但是当尝试捕获输入不匹配异常(如果像输入字符或字符串一样)时,循环只是无限运行,要求“星期一费用:”我如何使它,以便用户有另一个回答的机会?我试着Rest一下;但是这也打破了做而循环,我不想要。 这是我目前为止的代码: 谢谢你的帮助

  • 问题内容: 当我在 while循环中 使用 try和catch 块时,我的程序有一个无限 循环 。 当我输入一个整数时,它运行良好并要求另一个输入,但是当我输入一个字符时,它将进入无穷循环。为什么会这样呢? 问题答案: 遇到无效输入时,由于nextInt()不使用无效令牌,因此程序进入无限循环。因此,导致该异常的任何令牌都将保留在该位置,并在下次尝试使用nextInt()时继续引发异常。 可以通过

  • 所以我这里有一个程序,它只是简单地模仿跳棋(但不是跳,而是一个棋子简单地“吃掉”另一个棋子)。我有一个简单的类,它实现了一个“checkers”类对象,并创建了一个名为“chips”的int数组变量。还有一个“while”语句,它在chip[0]和chips[1]整数大于0时创建了一个循环。看起来是这样的: Checkers类中的count方法如下所示: 板是8 x 8(这就是board.leng

  • 我试图通过将ajax请求中的for循环的值发送到php文件来检查数据库中的值,“each value in request”,然后文件返回变量“avl”,如果不是,则不可用。 问题是,我检查了一个值流,它们都必须返回才能继续我的过程,但条件不会等到for循环结束才进行检查。它在for循环启动之前检查条件,即使代码也不是那样的。例如:在for循环在第50行结束之前,它在第100行执行条件。 它总是通