jjzjj

java - lambda 中的无限 while 循环内的 Thread.sleep 不需要 'catch (InterruptedException)' - 为什么不呢?

coder 2023-05-13 原文

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

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

使用此代码,编译器不会给我任何错误或消息,告诉我应该从 Thread.sleep 捕获 InterruptedException。但是当我试图改变循环条件并用这样的变量替换“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<?>功能接口(interface)(调用第一个重载方法);并且在您的问题的第二种情况下,将 lambda 转换为 Runnable功能接口(interface)(因此调用第二个重载方法),因此需要处理 Exception抛出;但不是在前面的情况下使用 Callable .

虽然两个函数式接口(interface)都不带任何参数,Callable<?> 返回一个值:

  1. Callable: V call() throws Exception;
  2. Runnable: 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();
    });

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

在这两种情况下,lambda 体都是 void-compatible ,因为 block 中的每个 return 语句都具有 return; 的形式.

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

  1. 检测到 lambda 中的所有执行路径都声明抛出 checked exceptions (从现在开始,我们将称为 'exception',仅表示 'checked exceptions')。这包括调用任何声明抛出异常的方法和显式调用 throw new <CHECKED_EXCEPTION>() .
  2. 正确地得出结论,lambda 的 WHOLE 主体等同于声明抛出异常的代码块;当然必须是:处理或重新抛出。
  3. 由于 lambda 不处理异常,因此编译器默认假定必须重新抛出这些异常。
  4. 安全地推断此 lambda 必须匹配功能接口(interface)不能 complete normally因此是 value-compatible .
  5. Callable<?> 起和 Runnable是此 lambda 的潜在匹配项,编译器选择最具体的匹配项(以涵盖所有场景);这是Callable<?> ,将 lambda 转换为它的实例并创建对 submit(Callable<?>) 的调用引用重载方法。

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

  1. 检测到 lambda 中可能存在 DO NOT 声明抛出异常的执行路径(取决于待评估逻辑)。
  2. 由于并非所有执行路径都声明抛出异常,编译器得出结论,lambda 的主体不一定相当于声明抛出异常的代码块 - 编译器不关心/注意是否代码的某些部分确实声明它们可以,只有当整个 body 都这样做或不这样做时。
  3. 安全地推断出 lambda 不是 value-compatible ;因为它可能 complete normally .
  4. 选择 Runnable (因为它是 lambda 要转换成的唯一可用的 fitting 功能接口(interface))并创建对 submit(Runnable) 的调用引用重载的方法。所有这一切都以委托(delegate)给用户为代价,负责处理任何 Exception s 在 lambda 主体部分可能出现的任何地方抛出。

这是一个很好的问题 - 我在追查它时玩得很开心,谢谢!

关于java - lambda 中的无限 while 循环内的 Thread.sleep 不需要 'catch (InterruptedException)' - 为什么不呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56149752/

有关java - lambda 中的无限 while 循环内的 Thread.sleep 不需要 'catch (InterruptedException)' - 为什么不呢?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  4. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  7. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  8. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  9. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  10. ruby - rspec 需要 .rspec 文件中的 spec_helper - 2

    我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只

随机推荐