一、异常
在程序运行过程中,会发生各种非正常的状况,比如程序运行时空间不足,网路连接中断,被装载的类不存在等,针对这种情况,在Java中引入了异常,以异常类的i形式对这些非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理。
二、异常处理
1、try....catch
try代码块中编写可能发生异常的Java语句,catch代码块中编写针对异常进行处理的代码,当try代码块中的程序发生了异常,系统会将这个异常的信息封装成一个异常对象,并将这个对象传给catch代码块。catch代码块需要一个参数指明它所能够接受的异常类型,这个参数的类型必须是Exception类或其子类。
如接下来的代码:
public class Example {
//实现了两个整数相除的方法
public static int divide(int x, int y) {
int result = x / y;
return result;
}
public static void main(String[] args) {
//定义一个try…catch语句用于捕获异常
try {
int result = divide(4, 0); //调用divide()方法
System.out.println(result);
} catch (Exception e) { //对异常进行处理
System.out.println("捕获的异常信息为:" + e.getMessage());
}
System.out.println("程序继续向下执行...");
}
}
结果:
如果没有try....catch的结果
可以看到使用try....catch后,可以返回异常信息,更便于找到错误信息。
注意:
①try代码块中,发生异常语句后面的代码是不会被执行的。如下面这句话没有执行
System.out.println(result);
②在catch代码块对异常处理完毕后,程序仍会向下执行。如下面这句话执行了
System.out.println("程序继续向下执行...");
2、finally:
有时候我们希望有些语句无论是否发生异常都要执行,这时就可以在try....catch后,加一个finally代码块。即使发生异常,catch语句中有return语句结束程序,finally里的语句仍然可以执行。如下面代码
public class Example2 {
public static void main(String[] args) {
//定义try…catch…finally语句用于捕获异常
try {
int result = divide(4, 0); //调用divide()方法
System.out.println(result);
} catch (Exception e) { //对捕获到的异常进行处理
System.out.println("捕获的异常信息为:" + e.getMessage());
return; //用于结束当前语句
} finally {
System.out.println("即使catch语句中return这条语句仍会");
}
System.out.println("程序继续向下执行…");
}
//下面的方法实现了两个整数相除
public static int divide(int x, int y) {
int result = x / y; //定义一个变量result记录两个数相除的结果
return result; //将结果返回
}
}
结果
捕获的异常信息为:/ by zero
即使catch语句中return这条语句仍会
3、throws关键字
①在定义一个方法时可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而是交给方法的调用处进行处理。
但管是否会产生异常,在调用方法处都必须进行异常处理。
若没有异常处理,编译错误,如下面代码(即使没有错误,但因没有异常处理,就错了)
public class Example {
public static void main(String[] args) {
int result = divide(4, 2); //调用divide()方法,这里没有异常处理,错了
System.out.println(result);
}
//实现两个整数相除,并使用throws关键字声明抛出异常
public static int divide(int x, int y) throws Exception {
int result = x / y; //定义一个变量result记录两个数相除的结果
return result; //将结果返回
}
}
若加上异常处理,就对了,哈哈,如下面代码
public class Example {
public static void main(String[] args) {
//下面的代码定义了一个try…catch语句用于捕获异常
try {
int result = divide(4, 2); //调用divide()方法
System.out.println(result);
} catch (Exception e) { //对捕获到的异常进行处理
e.printStackTrace(); //打印捕获的异常信息
}
}
//下面的方法实现了两个整数相除,并使用throws关键字声明抛出异常
public static int divide(int x, int y) throws Exception {
int result = x / y; //定义一个变量result记录两个数相除的结果
return result; //将结果返回
}
}
结果:
②在上例中,当调用divide()方法时,如果不知道如何处理声明抛出的异常,也也可以使用throws关键字继续抛出异常,如下代码
public class Example2 {
public static void main(String[] args)throws Exception {
int result = divide(4, 0); // 调用divide()方法
System.out.println(result);
}
// 下面的方法实现了两个整数相除,并使用throws关键字声明抛出异常
public static int divide(int x, int y) throws Exception {
int result = x / y; // 定义一个变量result记录两个数相除的结果
return result; // 将结果返回
}
}
结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at pocket1.Example2.divide(Example2.java:10)
at pocket1.Example2.main(Example2.java:5)
③在上面的代码中,不管是否有问题都要使用try...catch块进行异常处理,throws在主方法中也是可以使用throws关键字,但是主方法是程序的起点,所以此时主方法再向上抛异常,则只能抛给JVM进行处理,我们就可以使用try...catch块进行异常处理,如下代码
public class Example2 {
public static void main(String[] args)throws Exception {
int result = divide(4, 2); // 调用divide()方法
System.out.println(result);
}
// 下面的方法实现了两个整数相除,并使用throws关键字声明抛出异常
public static int divide(int x, int y) {
int result = x / y; // 定义一个变量result记录两个数相除的结果
return result; // 将结果返回
}
}
结果:2
4、自定义异常
虽然Java中定义了大量的异常类,可以描述编程时出现的大部分异常情况,但是再程序开发中有时可能需要描述程序中特有的情况。例如在设计divide()方法时,不允许被除
数为负数,为解决这个问题,在Java中允许用户自定义异常。
自定义的异常必须继承字Exception或其子类。如下面代码
class DivideByMinusException extends Exception{
public DivideByMinusException (){
super(); // 调用Exception无参的构造方法
}
public DivideByMinusException (String message){
super(message); // 调用Exception有参的构造方法
}
}
public class Example2 {
public static void main(String[] args) {
// 下面的代码定义了一个try…catch语句用于捕获异常
try {
int result = divide(4, -2); // 调用divide()方法,传入一个负数作为被除数
System.out.println(result);
} catch (DivideByMinusException e) { // 对捕获到的异常进行处理
System.out.println(e.getMessage()); // 打印捕获的异常信息
}
}
// 下面的方法实现了两个整数相除,并使用throws关键字声明抛出自定义异常
public static int divide(int x, int y) throws DivideByMinusException {
if (y < 0) {
throw new DivideByMinusException("被除数是负数");// 使用throw关键字声明异常对象
}
int result = x / y; // 定义一个变量result记录两个数相除的结果
return result; // 将结果返回
}
}
结果:被除数是负数
5、Java中的异常链
package tcy01;
public class ChainTest{
/*
*test1():抛出异常
*test2():调用test1(),捕获test1()抛出的异常,并且包装成运行时异常,继续抛出
*main方法中,调用test2(),尝试test2()方法抛出的异常。
*/
public static void main(String[] args){//main方法调用test2(),尝试test2()方法抛出的异常。
ChainTest ct=new ChainTest();
try{
ct.test2();
}catch(Exception e){
e.printStackTrace();
}
}
public void test1() throws DefineException{
throw new DefineException("test1()抛出的异常");
}
public void test2(){ //test2()调用test1(),捕获test1()抛出的异常
try{
test1();
}catch(DefineException e){
RuntimeException newExc=new RuntimeException("test2()中抛出的异常");
newExc.initCause(e); //包装成运行时异常
throw newExc; //继续抛出异常
}
}
}
结果:
java.lang.RuntimeException: test2()中抛出的异常
at tcy01.ChainTest.test2(ChainTest.java:25)
at tcy01.ChainTest.main(ChainTest.java:12)
Caused by: tcy01.DefineException: test1()抛出的异常
at tcy01.ChainTest.test1(ChainTest.java:19)
at tcy01.ChainTest.test2(ChainTest.java:23)
... 1 more