《Java异常处理》学习笔记

时间:2020-12-06 15:35:28

1.异常处理对性能的影响
一般来说,在Java程序中使用try…catch语句不会对应用的性能造成很大的影响。仅仅当异常发生时,Java虚拟机需要执行额外的操作,来定位处理异常的代码块,这是会对性能产生负面影响。如果抛出异常的代码块和捕获异常的代码块位于同一个方法中,这种影响就会小一些;如果Java虚拟机必须搜索方法调用栈来寻找异常处理代码块,对性能的影响就比较大了。尤其当异常处理代码块位于调用栈的底部时,Java虚拟机定位异常处理代码块就需要大量的工作。

2.运用Java异常处理机制

  • 在Java语言中,用try…catch语句来捕获异常。
  • finally语句:任何情况下都必须执行的代码
  • throws子句:声明可能会出现的异常。如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明跑出异常。
  • throw语句:抛出异常
    例如:汽车在运行时可能会出现故障,汽车本身没办法处理这个故障,因此Car类的run方法声明抛出异常 CarWrongExcepiton:
    public void run() throws CarWrongException {
if(车子无法刹车)
throw new CarWrongException("车子无法刹车");
if(发动机无法启动)
throw new CarWrongException("发动机无法启动");
}

异常处理语句的语法规则

  • try代码块不能脱离catch代码块或finally代码块而单独存在。try代码块后面至少有一个catch代码块或finally代码块
  • try代码块后面可以有零个或多个catch代码块,还可以有零个或至多一个finally代码块。如果catch代码块和finally代码块并存,finally代码块必须在catch代码块后面
  • try代码块后面可以只跟finally代码块
    try {
int a = 1;
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
a--; //编译错误
} finally {
a ++; //编译错误
}
  • 如果一个方法可能出现受检查异常,要么用try…catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误
  • throw语句后面不允许紧跟其它语句,因为这些语句永远不会被执行。例:
    try {
int a = 1;
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
throw e;
a --;
}

异常流程的运行过程

  • finally语句不被执行的唯一情况是先执行了用于终止程序的System.exit()方法。exit方法的参数表示程序终止时的状态码,按照编程惯例,0表示正常终止,非0表示异常终止。
    正常流程:
    try {
System.out.println("Beginning ......");
} finally {
System.out.println("Finally ......");
}
正常输出结果:
Beginning ......
Finally ......
使用exit方法后代码:
    try {
System.out.println("Beginning ......");
System.exit(0);
} finally {
System.out.println("Finally ......");
}
输出结果:
Beginning ......
  • return语句用于退出本方法。在还行try或catch代码块中的return语句是,加入有finally代码块,会先执行finally代码块。
    例:
        try {
Object ob = null;
ob.equals("name");
System.out.println("Beginning ......");
return;
} catch (Exception e) {
System.out.println("catch exception ......");
return;
} finally {
System.out.println("finally is ......");
}
 运行结果如下:
catch exception ......
finally is ......
  • finally代码块虽然在return语句之前被执行,但finally代码块不能通过重新给变量赋值的方式来改变return语句的返回值。
    例:
    public static void main(String[] args) {
System.out.println("get value is : " + test());
}

public static int test() {
int a = 10;
try {
System.out.println("Beginning ......");
return a;
} finally {
System.out.println("finally is ......");
a = -10;
}
}
运行结果如下:
Beginning ......
finally is ......
get value is : 10
  • 建议不要在finally代码块中使用return语句,因为它会导致以下两种潜在的错误。第一种错误是覆盖try或catch代码块中的return语句,如下例所示:
    public static void main(String[] args) {
System.out.println("get value is : " + test());
}

public static int test() {
int a = 10;
try {
System.out.println("Beginning ......");
return a;
} finally {
System.out.println("finally is ......");
a = -10;
return a;
}
}
运行结果为(预期应该返回10,但是被finally中的return语句覆盖了):
Beginning ......
finally is ......
get value is : -10
  • 第二种错误是丢失异常,如下例所示:
public class ExLoss {
class SpecialException extends Exception {
public SpecialException(String resean) {
System.out.println("get exception is : " + resean);
}
}

public int methodA(int money) throws SpecialException{
if (--money <= 0) {
throw new SpecialException("out of money");
}
return money;
}

public int methodB(int money) throws Exception {
try {
return methodA(money);
} catch (SpecialException e) {
throw new SpecialException("wrong");
} finally {
return 100;
}
}
}

public class HelloWorld {
public static void main(String[] args) {
try {
System.out.println(new ExLoss().methodB(0));
System.out.println("No Exception");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
运行结果如下(没有返回异常,与预期不一致):
get exception is : out of money
100
No Exception
分析说明:methodB()方法的catch代码块继续抛出异常,按理说main()方法的catch代码块应该捕获并处理该异常,但由于methodB()方法的finally代码块有返回值,异常被丢失了,main()方法没有捕获到methodB()方法的异常

-