前提
通常我们在代码中捕获错误异常,使用的是try{ }catch{ }
机制,今天在看项目时,突然发现里面使用try{ }finally{ }
捕获异常,这种方法之前使用的还不是很多,所以也查了资料,深入研究研究。
try finally
(1)语法
异常机制中还有一个重要的部分,就是finally。
catch后面可以跟finally语句,语法如下所示:
try{
//可能抛出异常
}catch(Exception e){
//捕获异常
}finally{
//不管有无异常都执行
}
finally内的代码不管有无异常发生,都会执行。
(2)运行机制
- 如果
没有异常
发生,在try内的代码
执行结束后
,就执行finally内代码
- 如果
有异常
发生且被catch捕获
,在catch内的代码
执行结束后,就执行finally内代码
- 如果
有异常
发生但没被捕获
,则在异常被抛给上层之前执行
值得注意的是,try/catch/finally语法中,catch不是必需的
,也就是可以只有try/finally
,表示不捕获异常
,异常自动向上传递
,但finally中的代码在异常发生后也执行
。
(3)return
(1)try中有return
在try / catch / finally 语句里面,有一个细节,就是如果在try或者catch内有return
,则这时return
语句会在finally语句执行结束后才会执行
,但是finally并不能立即改变返回值
,我们可以看下面代码:
import React , { useState , useEffect} from 'react';
const App = () => {
const [val , setVal] = useState(0)
const getResult = () => {
try {
return setVal(1234)
} catch (error) {
console.log('error',error)
}finally{
setVal(9999)
}
}
useEffect(() => {
getResult()
}, [])
return (
<div>
<h1>
哈哈啊哈哈哈
</h1>
<h2>
当前的val值:{val}
</h2>
</div>
);
};
export default App;
效果图:
可以看出:
这个函数的返回值是9999,而不是1234。实际执行过程是:
- 在执行到try内的
return setVal(1234)语句前时
,会先将返回值val保存在一个临时变量
中 - 然后才
执行finally语句
- 最后
try再返回那个临时变量
,finally中对val的修改不会被返回
(2)finally中有return
如果在finally中也有return语句呢,这时会是什么情景呢?
如果finally里面
也含有return
,那么try和catch内的return会丢失
,实际会返回finally中的返回值
。
事实上,finally中有return
不仅会覆盖try和catch内的返回值
,还会掩盖try和catch内的异常
,就像异常没有发生一样,比如说:
import React , { useState , useEffect} from 'react';
const App = () => {
const [val , setVal] = useState(0)
const getResult = () => {
try {
let aaa = 111/0
return setVal(aaa)
} catch (error) {
console.log('error',error)
}finally{
setVal(9999)
}
}
useEffect(() => {
getResult()
}, [])
return (
<div>
<h1>
哈哈啊哈哈哈
</h1>
<h2>
当前的val值:{val}
</h2>
</div>
);
};
export default App;
效果图:
可以发现:
- try里面的函数有错误,但是并没有异常抛出。
- finally里面的return把错误给覆盖掉了,而且不再向上传递。
其实,finally中不仅return语句会掩盖异常,如果finally中抛出了异常,则原异常就会被掩盖,看下面代码:
import React , { useState , useEffect} from 'react';
const App = () => {
const [val , setVal] = useState(0)
const getResult = () => {
try {
let aaa = 111/0
return setVal(aaa)
} catch (error) {
console.log('error',error)
}finally{
let bbb = 33/0
// throw new Error('出错了')
return (
setVal(bbb),
console.log('finally error')
)
}
}
useEffect(() => {
getResult()
}, [])
return (
<div>
<h1>
哈哈啊哈哈哈
</h1>
<h2>
当前的val值:{val}
</h2>
</div>
);
};
export default App;
效果图:
可以发现:
- finally里面抛出了错误
所以,一般而言,为避免混淆,应该避免在finally中使用return语句
或者抛出异常
,如果调用的其他代码可能抛出异常,则应该捕获异常并进行处理。