try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。(catch中如果发生异常会抵消捕获的异常,总之最后一处发生的异常会被抛出,包括finally块)
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
catch 块:用于处理try捕获到的异常。(catch中如果发生异常会抵消捕获的异常,总之最后一处发生的异常会被抛出,包括finally块)
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
1.throw和return都可以使方法退出,而且可以互相覆盖
2.finally里如果有return会把catch里面throw出来的异常覆盖掉
public
static
int
testInt
()
throws
Exception
{
int
x
;
try
{
x
=
1
;
throw
new
Exception
()
;
// return x;
}
catch
(
Exception
e)
{
x
=
2
;
throw
e
;
}
finally
{
x
=
3
;
return
x
;
}
}
3.程序运行关于栈和堆的问题,大家最好弄懂,无论那个编程语言都会涉及到,c里面叫指针,更高级语言里面叫引用,不懂这些有很多问题好难懂。了解这个问题的时候不要因为别人举例的语言不是java就抛弃,其实高级语言基础语法都差不多,不是蛮难看懂但是思想好重要
public
static
int
testInt
(){
int
x
;
try
{
x
=
1
;
return
x
;
}
catch
(
Exception
e)
{
x
=
2
;
return
x
;
}
finally
{
x
=
3
;
// System.out.println("x:" + x);// return x;
// }
}
}
这是《深入理解Java虚拟机-JVM高级特性与最佳实践》第二版书中的例子(P187~P188)。出现这种情况的原因是:在没有出线异常的情况下,先执行了x=1;然后执行return x;时,首先是将x的一个副本保存在本地变量表中,执行return之前必须执行finally中的操作:x=3;将x的值设置为了3,但是return时是将本地变量表中保存的x的那个副本拿出来放到栈顶返回。故没出异常时,返回值为1;出Exception异常或其子类异常时,返回值是2;如果出现非Exception异常,则执行完x=3之后,抛出异常,没有返回值。
对于这种异常时的执行情况,可以通过javap -verbose命令输出方法反编译后的字节码与异常表,从字节码层面上就能清晰的看出执行过程了。
return之前执行finally的话,return是返回了栈内存的副本(primitive类型数据副本 ,引用类型引用的副本),所以finally块如果操作的事primitive类型数据,或者重新分配了引用,String="456",会重新创建一个对象,所以不会影响引用副本。
public
static
int
testInt
()
throws
Exception
{
int
x
;
try
{
x
=
1
;
throw
new
Exception
(
"111"
)
;
// return x;
}
catch
(
Exception
e)
{
x
=
2
;
//
throw
new
Exception
(
"222"
)
;
return x;//返回x的副本(
primitive类型数据
)所以不会被finally块影响 return x=2
}
finally
{
x
=
3
;
// throw new Error();
// System.out.println("x:" + x);
// return x;
}
}
//引用类型的例子,
public
static
String
testString
(){
String
name
=
"123"
;
try
{
throw
new
Exception
()
;
//return name;
}
catch
(
Exception
e)
{
return
name
;//返回引用副本(对象类型)finally块name="456",是重新分配了引用 return name='123'
}
finally
{
name
=
"456"
;
}
}
static
StringBuffer
testStringBuffer
(){
StringBuffer
name
=
new
StringBuffer
(
"123"
)
;
try
{
throw
new
Exception
()
;
}
catch
(
Exception
e)
{
System
.
out
.
println
(
"catch name123: "
+
name
.
hashCode
())
;
return
name
;
//返回引用副本(对象类型)finally块name.append("456"),是对同一块引用的堆值得追加,所以影响了return name='123456'
}
finally
{
name
.
append
(
"456"
)
;
System
.
out
.
println
(
"finally name456: "
+
name
.
hashCode
())
;
name
=
new
StringBuffer
(
"abc"
)
;
System
.
out
.
println
(
"finally name: "
+
name
.
hashCode
())
;
}
}
static
StringBuffer
testStringBuffer
()
throws
Exception
{
StringBuffer
name
=
new
StringBuffer
(
"123"
)
;
try
{
throw
new
Exception
()
;
}
catch
(
Exception
e)
{
System
.
out
.
println
(
"catch name123: "
+
name
.
hashCode
())
;
return
name
;
}
finally
{
name
.
append
(
"456"
)
;
System
.
out
.
println
(
"finally name456: "
+
name
.
hashCode
())
;
name
=
new
StringBuffer
(
"abc"
)
;
System
.
out
.
println
(
"finally name: "
+
name
.
hashCode
())
;
throw
new
Exception
()
;
//抛出异常(抵消前面的所有异常)
}
}