您的位置:首页 > 编程语言 > Java开发

我所理解的JDK异常(二):try-catch-finally的使用

2017-12-31 11:44 459 查看
记录一些关于try-catch-finally的使用:

1,try{}中如果没有发生异常,catch{}不会执行;

try{}中如果发生异常,catch{}执行;

无论try{}是否发生异常,finally{}都会执行。

public class TestFinally {

public static void main(String[] args) {
TestFinally testFinally = new TestFinally();
testFinally.tryCauseExceptionMethod();
System.out.println("========================");
testFinally.tryNotCauseExceptionMethod();
}

private void tryCauseExceptionMethod(){
try{
System.out.println("try start");
int a = 1 / 0;
System.out.println("try end");
}catch(Exception e){
System.out.println("catch");
}finally{
System.out.println("finally");
}
}

private void tryNotCauseExceptionMethod(){
try{
System.out.println("try");
}catch(Exception e){
System.out.println("catch");
}finally{
System.out.println("finally");
}
}
}

控制台输出:

try start
catch
finally
========================
try
finally

2,子类异常不会捕获父类异常。父类异常可以捕获子类异常。

try {
int a = 1 / 0;
} catch (MyFirstException e) {
System.out.println("fist");
}

class MyFirstException extends ArithmeticException{}

以上代码无法捕获异常。

3,try、catch、finally中都可以抛出异常,不管是编译器异常还是运行期异常。

如果try中抛出的异常可以被catch捕获,则try中抛出的该异常永远不会被方法调用者捕获。

如果catch中抛出了异常,catch的异常会正常抛出并打印,方法调用者可以捕获catch抛出的该异常。线程可以正常执行。

如果finally中抛出异常,则相当于整个try-catch-finally抛出了异常。

public class TestMCatch {

public static void main(String[] args) {
TestMCatch testCatch = new TestMCatch();
try {
testCatch.myCatch();
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("cath the method throw");
}
System.out.println("even exception happend, the thread still excute");
}

private void myCatch() throws FileNotFoundException{

try {
throw new FileNotFoundException("try throw exception");
} catch (Exception e) {
System.out.println("catch try throw, msg: " + e.getMessage());
throw new FileNotFoundException("catch throw exception");
}

}
}

控制台输出:

catch try throw, msg: try throw exception
cath the method throw
even exception happend, the thread still excute
java.io.FileNotFoundException: catch throw exception
at cn.testException.TestMCatch.myCatch(TestMCatch.java:30)
at cn.testException.TestMCatch.main(TestMCatch.java:15)

4,多个catch{}中,catch是有顺序关系的,且只能被捕获一次。

如果异常具有继承关系,则子类不能出现在父类后,否则编译器不通过。

如果catch的异常彼此意见不具有继承关系,则按照顺序,先匹配的先执行。

(由于java中只能是单继承,所以所有catch中最近接异常的catch会被执行)

try {
int a = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
} catch (ArithmeticExceptione) {
e.printStackTrace();
}

以上代码编译不通过。

try {
int a = 1 / 0;
} catch (ArithmeticException e) {
System.out.println("the ArithmeticException catch");;
} catch (Exception e) {
System.out.println("the Exception catch");;
}

控制台输出:

the ArithmeticException catch

5,catch中捕获到异常后,可能再次throw,并且可以把当前的Exception作为构造参数传递,方法调用者捕获后,e.printStackTrace(),控制台会有Caused by 产生。

public class TestReturn {

public static void main(String[] args) {
TestReturn testReturn = new TestReturn();
try {
int a = testReturn.testReturnMethod();
System.out.println(a);
} catch (Exception e) {
e.printStackTrace();
}
}

private int testReturnMethod(){
int a = 1;
try {
a = 1 / 0;
return a;
} catch (Exception e) {
a = 9;
throw new RuntimeException(e);
} finally {
a = 11;
}
}

}

控制台输出:

java.lang.RuntimeException: java.lang.ArithmeticException: / by zero
at cn.testException.TestReturn.testReturnMethod(TestReturn.java:26)
at cn.testException.TestReturn.main(TestReturn.java:12)
Caused by: java.lang.ArithmeticException: / by zero
at cn.testException.TestReturn.testReturnMethod(TestReturn.java:22)
... 1 more

6,try-catch-finally与return结合的情况,稍微复杂一些。

首先,方法中经常return的数据分为3类:1.基础数据类型;2.基础数据类型对应的包装类以及String这样的JDK中原生支持的final类;3.其他的普通的POJO类。

为什么要分为这3类呢?1.对于基础类型数据,在Java中调用的数据传递是值传递;2.对于Object类型,在Java中调用的数据传递是引用传递,传递的是内存空间的地址值。

那为什么还要分为final和非final呢?因为final类的实例对象的地址值是不可更改的。比如:

Integer a = 0; // 堆空间中开辟一块空间,并把new Integer(0)的引用赋给a
Integer a = 1; // 堆空间中开辟一块空间,并把new Integer(1)的引用赋给a,原来的new Integer(0)的空间等待被回收

正是因为Integer是final类的,它的改变是需要改变引用地址的。

可是这根本文讨论的try-catch-finally有关系吗?还真有。

6.1,如果finally中有return,则renturn的是finally中的数据。

public static void main(String[] args) {
TestReturn testReturn = new TestReturn();
System.out.println(testReturn.testReturnMethod());
}

private int testReturnMethod(){
int a = 1;
try {
a = 10;
return a;
} catch (Exception e) {
a--;
return a;
} finally {
a++;
return a;
}
}

控制台输出: 11

6.2,如果finally中没有return

6.2.1,如果try中有return,return的是基本数据类型,则finally中的修改不会对原return值改变。

public static void main(String[] args) {
TestReturn testReturn = new TestReturn();
System.out.println(testReturn.testReturnMethod());
}

private int testReturnMethod(){
int a = 1;
try {
a = 10;
return a;
} catch (Exception e) {
a--;
return a;
} finally {
a++;
}
}

控制台输出: 10

6.2.2,如果try中有return,return的是基本数据类型的包装类以及String这样的JDK中原生支持的final类,则finally中的修改不会原return值改变。

public static void main(String[] args) {
TestReturn testReturn = new TestReturn();
System.out.println(testReturn.testReturnMethod());
}

private String testReturnMethod(){
String a = "a";
try {
a = "b";
return a;
} catch (Exception e) {
a = "c";
return a;
} finally {
a = "d";
}
}

控制台输出: b

6.2.3,如果try中有return,return的是普通的POJO类型,这finally对该POJO的修改会影响原return的值。

public class TestReturn {

public static void main(String[] args) {
TestReturn testReturn = new TestReturn();
User u = new User("lily");
System.out.println(testReturn.testReturnMethod(u).getName());
}

private User testReturnMethod(User u){
try {
u.setName("try");
return u;
} catch (Exception e) {
return u;
} finally {
u.setName("finally");
}
}

}

class User {
private String name;
public User(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

控制台输出:finally

6.3,总结:try中的retrun拿到最终要return的值,然后进入finally执行。只要finally中没有return,无论finally如何更改,最终要return的值是不会变的(要么是基础数据类型的值,要么是内存空间的地址值)。如果有兴趣反编译的话,可以验证。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: