雁过留声

a tiger in me sniffs roses

0%

异常中的finally

异常处理中,在捕获异常后还可以再次抛出异常,也可以在catch中return,那在finally中是否还可以再次抛出异常、是否可以return,下面是测试几种常用语言的结果总结

js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function test_except() {
try{
let a = undefined
a.b()
}
catch {
console.log('ex catched')
}
finally {
console.log('finally')
throw 'error' //会throw error, 让return 不会执行
return 1 //如果没有throw,会被执行,return 2不可达
}
return 2
}

可以throw,可以return且throw、return后的语句都不可达

python

1
2
3
4
5
6
7
8
9
10

def test_except():
try:
a = 1/0
except:
print('ex catched')
finally:
# raise Exception('error')
return 1
return 2

同js

java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static int test_except() throws Exception {
try {
float a = 1 / 0;
}
catch(Exception e) {
System.out.println("ex catched");
}
finally {
System.out.println("finally");
throw new Exception("error");
// return 1;
}
// return 2; //throw会让这里变成语法错误
}

行为和js一致,但是在throw或者return后的不可达代码被认为是语法错误

ruby

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/ruby -w

def test_except
begin
a = 1 / 0
puts a
rescue Exception => e
puts e.message
# retry
else
# 没有异常时候的块
puts 'else in except'
ensure
puts 'finally'
raise 'error again'
return 1
end
return 2
end

ensure 等于 finally,行为和js一致。

c#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public int test_except(int num)
{
int result = 0;
try
{
result = 1 / num;
}
catch (DivideByZeroException e)
{
Console.WriteLine("except catched: {0}", e);
}
finally
{
Console.WriteLine("Result: {0}", result);
throw new Exception("error");
// return 1; //语法错误
}
return 2; //throw会使return不会被执行,但不是语法错误
}

finally中都可以再抛出异常,但不应当这么做,finally用于确保资源的正确释放。特别地:C# 不能从finally中return,而其它几个语言finally块中的代码和其它地方代码没什么特别,只是在有、无异常都会被调用的语法糖。
注意:c++没有finally,在C++中通常使用RAII(Resource Aquisition Is Initialization).就是将资源封装成一个类,将资源的初始化封装在构造函数里,释放封装在析构函数里。通过局部变量析构函数总是会被调用的特性实现