Java Thread.sleep在无限范围内,而lambda中的循环不';不需要';捕获(中断异常)和#x27;-为什么不呢?
我的问题是关于Java Thread.sleep在无限范围内,而lambda中的循环不';不需要';捕获(中断异常)和#x27;-为什么不呢?,java,multithreading,lambda,compilation,functional-interface,Java,Multithreading,Lambda,Compilation,Functional Interface,我的问题是关于InterruptedException,它是从线程.sleep方法抛出的。在使用ExecutorService时,我注意到一些我不理解的奇怪行为;我的意思是: ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(() -> { while(true) { //DO SOMETHING
InterruptedException
,它是从线程.sleep
方法抛出的。在使用ExecutorService时,我注意到一些我不理解的奇怪行为;我的意思是:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
while(true)
{
//DO SOMETHING
Thread.sleep(5000);
}
});
使用这段代码,编译器不会给我任何错误或消息,说明InterruptedException
来自Thread.sleep
应该被捕获。但当我试图更改循环条件并用如下变量替换“true”时:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
while(tasksObserving)
{
//DO SOMETHING
Thread.sleep(5000);
}
});
编译器不断抱怨必须处理
InterruptedException
。有人能给我解释一下为什么会发生这种情况,以及为什么如果条件设置为true,编译器会忽略InterruptedException吗?原因是,这些调用实际上是对ExecutorService
中提供的两个不同重载方法的调用;每个方法都采用不同类型的单个参数:
未来提交(可调用任务)代码>
未来提交(可运行任务)代码>
可运行的
函数接口(因此调用第二个重载方法),因此需要处理抛出的异常
;但在前一种情况下,不能使用可调用的
尽管两个函数接口都不接受任何参数,Callable
返回一个值:
V call()引发异常代码>
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();
});
ExecutorService executor=Executors.newSingleThreadExecutor();
//LAMBDA编译为“可调用”
执行人提交(()->{
while(true)
抛出新异常();
});
//LAMBDA编译为“可运行”:异常必须由LAMBDA本身处理!
执行人提交(()->{
布尔值=真;
while(值)
抛出新异常();
});
通过这些示例,可以更容易地观察到第一个转换为可调用的
,而第二个转换为可运行的
的原因是编译器推断
在这两种情况下,lambda主体都是,因为块中的每个return语句的形式都是return代码>
现在,在第一种情况下,编译器执行以下操作:
检测lambda中的所有执行路径声明抛出(从现在起,我们将称为“异常”,仅表示“已检查的异常”)。这包括调用任何声明抛出异常的方法,以及显式调用thrownew()
正确地得出结论,lambda的整个主体相当于一个声明抛出异常的代码块;当然,必须处理或重新抛出
由于lambda没有处理异常,因此编译器默认假定必须重新引发这些异常
安全地推断,此lambda必须与功能接口匹配,不能正常完成
,因此是
Callable
和Runnable
是此lambda的潜在匹配项,因此编译器选择最具体的匹配项(以覆盖所有场景);它是Callable
,将lambda转换为它的实例,并创建对submit(Callable)
重载方法的调用引用Runnable
(因为它是lambda转换为的唯一可用的拟合功能接口),并创建对submit(Runnable)
重载方法的调用引用。所有这些都是以委托给用户为代价的,处理任何抛出的异常的责任可能发生在lambda主体的部分内
ExecutorService
同时具有submit(可调用)
和submit(可运行)
方法
while(true)
),submit(Callable)
和submit(Runnable)
都匹配,因此编译器必须在两者之间进行选择
被选择在submit(Callable)
之上,因为submit(Runnable)
比Callable
更具体Runnable
在Callable
中有call()
,因此不需要捕获其中的异常抛出异常
while(tasksObserving)
),只有submit(Runnable)
匹配,因此
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
while(true)
{
//DO SOMETHING
Thread.sleep(5000);
}
});
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
while(tasksObserving)
{
//DO SOMETHING
Thread.sleep(5000);
}
});