try是一个神奇的语句,它可以检测代码中发生的异常。一旦try检测到了异常,它就会在java堆里面创建一个异常对象,而catch也很神奇,它用来检查堆里是否有try创建的异常对象。
本来java虚拟机底层也可以发现到这些异常的,一旦发现了异常程序会停止。但是对于一些不可间断的服务,不能遇到点问题,就停止了。比如用户操作导致的数组越界或者除0运算,不能因为用户输错个数就导致程序崩了。
码农们利用try语句先于java虚拟机中检测异常的任务执行,提前处理掉了异常,让java虚拟机发现不到异常,因此也就不会导致程序终止。比如你考试打小抄的时候,班主任先于年级主任发现了你作弊,就制止了你,结果年级主任没有发现你作弊。
虽然是对你的保护,但是班主任还得在班级内部对你进行处分。一般采用catch或finally对try到的异常进行处理,类似于批评教育或者找家长。
try{语句}表示,如果语句里有异常,就在堆里创建异常的对象,如果没有异常,就不创建异常的对象。
而catch(ArithmeticException e){语句} 表示,如果堆里存在 ArithmeticException e这个对象,括号里面的语句就执行,如果不存在,括号里的语句就不执行。类似于if(e!=NULL){语句}。而ArithmeticException e是try在检测代码异常时,在堆里创建的。
如果你通过catch捕获到了异常对象,你会做些什么呢?标准的处理方式是打印日志信息,告诉维护序的人发生了什么错误。但这是一个开放性的脑洞,比如码农们通过写发告警短信的代码让运维人员能接收到告警,让运维功能瞬间高大上。
需要注意的是try捕获到不同的异常时会创建不同的异常对象。但是一条catch只能捕获一种异常对象,所以那么每catch到一种异常对象,就写一条catch?
try{
检测语句
}
catch(ArithmeticException e) {
System.out.println(“除数为0: ” + e);
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println(“访问越界: ” + e);
}
上面代码只写了2种异常,异常还有很多种,难道写个helloword就把所有异常都列一遍吗?除非你很关注某一类问题,比如jvm内存溢出,或者是网络异常,才会针对这种异常去写catch,一般情况下码农们按 Ctrl+Alt+t 生成通用的异常处理代码来捕获异常。
try {
代码;
} catch (Exception e) {
e.printStackTrace();
}
e.printStackTrace(); 是通用的异常打印语句,不管什么异常都能打印出来。你也不用再细分异常。但是这种代码显然是不够高大尚的。
如果在很多方法里都写try catch,看起来就会很乱,像是下面的代码。
public class ThreadLearn {
public static void main(String[] args) {
method1();
method2();
}
public static void method1() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void method2() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可以在方法后面写一条throws InterruptedException命令向外部抛异常检测的需求,在方法外面统一写try catch的代码。
public class ThreadLearn {
public static void main(String[] args) {
try {
method1();
method2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void method1() throws InterruptedException {
Thread.sleep(1000);
}
public static void method2() throws InterruptedException {
Thread.sleep(1000);
}
}
throws的好处是可以让代码变得简洁,只在最外层的代码写一个try catch就好了。需要注意的是throws InterruptedException是跟外面的try配套使用的,外面不写try无法通过编译。
有时try捕获到了异常,码农们打算释放资源关闭任务,这时就要用到finally这个命令。finally是在方法中的所有return语句之后执行的。
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
return a;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
return a;
}
}
执行结果为40。函数执行顺序是存储到栈里的,finally的操作是最先存储入栈的,倒数两次return a都入了栈,但是try里的return a 受到了异常操作的影响没有入栈。
如果把finally里的return a去掉,结果就是30。
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
return a;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
}
}
这是因为,虽然a=40是最后执行的,但是没有赋值给方法返回值,方法的返回值还是a=30时赋值的。