1 class Test 2 { 3 public int devide(int x,int y) 4 { 5 int result=x/y; 6 return result; 7 } 8 } 9 class TestException 10 { 11 public static void main(String [] args) 12 { 13 Test t=new Test(); 14 t.devide(2,0); 15 System.out.println("the program is running here!"); 16 } 17 } 18 /* 19 F:java_examplelesson61>java TestException 20 Exception in thread "main" java.lang.ArithmeticException: / by zero 21 at Test.devide(Test.java:5) 22 at TestException.main(Test.java:14) 23 */
上述代码中,由于除数为零,导致程序崩溃,后面的代码都不能执行。在实际工作中,或多或少会有各种异常出现,为了尽量避免,需要引入异常的处理机制。
经过异常处理之后,代码如下
1 class Test 2 { 3 public int divide(int x,int y) 4 { 5 int result=x/y; 6 return result; 7 } 8 } 9 class TestException 10 { 11 public static void main(String [] args) 12 { 13 Test t=new Test(); 14 try{ 15 t.divide(2,0);
System.out.println("the divide opration is over"); 16 } 17 catch(Exception e) 18 { 19 System.out.println(e.getMessage()); 20 } 21 System.out.println("the program is running here!"); 22 } 23 } 24 /* 25 F:java_examplelesson61>java TestException 26 / by zero 27 the program is running here! 28 */
在上述代码中,try的部分写入可能会发生异常的代码,异常发生后会直接转向执行catch部分代码,try中异常语句后面的代码会被忽略,如程序中的System.out.println("the devide operation is over!");语句不会被执行。整个执行流程是当try中的语句发生异常,程序会调用catch,执行完catch中的程序之后,系统会继续执行catch代码块后的其他代码。
当try代码块中的程序发生异常,系统将这个异常发生的代码行号、类别等信息封装到一个对象中,并将该对象传递给catch代码块。catch关键字后跟有一个Exception类型的参数e,这跟我们经常用到的,如何定义一个函数接收的参数格式是一样的。括号中的Exception就是try代码块传递给catch代码块的变量类型,e是变量名,也可以换成别的名称。
如果我们将catch中不写任何语句,是空的,那么当try中代码发生异常后,不会打印出任何异常信息,而很难让人觉察到程序的错误,所以这一步不能偷懒。
throws关键字
在实际工作中,代码不止是一个人编写的,前一个人编写了一个函数,另一个人需要调用,如果这个函数在调用过程中会发生异常,但是后面的人不知道,那么一场就很可能会发生并导致程序崩溃,那么我们就引入了throws关键字。写devide方法的人需要在定义该方法时加上throws 关键字,调用者在调用该方法时,加上try...catch语句进行处理。若只用throws声明,哪怕函数是正确被调用,没有写try...catch则程序编译无法通过,如下:
1 class Test 2 { 3 public int divide(int x,int y) throws Exception 4 { 5 int result=x/y; 6 return result; 7 } 8 } 9 class TestException 10 { 11 public static void main(String [] args) 12 { 13 Test t=new Test(); 14 //try{ 15 t.divide(2,1); 16 System.out.println("the divide opration is over"); 17 //} 18 /*catch(Exception e) 19 { 20 System.out.println(e.getMessage()); 21 }*/ 22 System.out.println("the program is running here!"); 23 } 24 } 25 /* 26 F:java_examplelesson61>javac Test.java 27 Test.java:15: 错误: 未报告的异常错误Exception; 必须对其进行捕获或声明以便抛出 28 t.devide(2,1); 29 ^ 30 1 个错误 31 */
将注释去掉之后,程序即可运行成功。
自定义异常与throw关键字
Exception类是java.lang.Throwable类的子类,Exception类继承了Throwable类的所有方法,在实际应用中,是使用Exception的子类来描述任何特定的异常。Exception类是所有异常类的父类,java中提供了常见的异常,比如:
ArithmeticException 在算术运算中发生的异常,如除数为零;
NullPointerException 空指针异常
ArrayIndexOutOfBoundsException 访问数组对象中存在的元素
除了系统定义的异常,我们也可以自己定义异常类,自定义的异常类必须继承Exception类
1 class Test 2 { 3 public int devide(int x,int y) throws Exception 4 { 5 if(y<0) 6 throw new DevideByMinusException("the divisor is negative "+y); 7 //这里抛出的异常对象,就是catch(Exception e)中的e 8 int result=x/y; 9 return result; 10 } 11 } 12 class DevideByMinusException extends Exception 13 { 14 public DevideByMinusException(String msg) 15 { 16 super(msg); 17 } 18 } 19 class TestException 20 { 21 public static void main(String [] args) 22 { 23 Test t=new Test(); 24 try{ 25 t.devide(2,-1); 26 System.out.println("the devide opration is over"); 27 } 28 catch(Exception e) 29 { 30 System.out.println(e.getMessage());//打印出the divisor is negative -1 31 e.printStackTrace(); 32 } 33 System.out.println("the program is running here!"); 34 } 35 } 36 /* 37 F:java_examplelesson61>java TestException 38 the divisor is negative -1 39 DevideByMinusException: the divisor is negative -1 40 at Test.devide(Test.java:6) 41 at TestException.main(Test.java:25) 42 the program is running here! 43 */
java通过throw关键字抛出异常对象,语法格式是:
throw 异常对象;
一个try后面可以有多个catch,try中语句出现了哪种异常,就去执行对应的catch
1 class Test 2 { 3 public int divide(int x,int y) throws ArithmeticException,DivideByMinusException 4 { 5 if(y<0) 6 throw new DivideByMinusException("the divisor is negative "+y); 7 //这里抛出的异常对象,就是catch(Exception e)中的e 8 int result=x/y; 9 return result; 10 } 11 } 12 class DivideByMinusException extends Exception 13 { 14 public DivideByMinusException(String msg) 15 { 16 super(msg); 17 } 18 } 19 class TestException 20 { 21 public static void main(String [] args) 22 { 23 Test t=new Test(); 24 try{ 25 t.divide(2,1); 26 System.out.println("the divide opration is over"); 27 } 28 catch(ArithmeticException e) 29 { 30 System.out.println("Error ~ ArithmeticException"); 31 e.printStackTrace();//Exception类中的方法 32 } 33 catch(DivideByMinusException e) 34 { 35 System.out.println("Error ~ DivideByMinusException"); 36 e.printStackTrace(); 37 } 38 catch(Exception e) 39 { 40 System.out.println(e.getMessage());//打印出the divisor is negative -1 41 e.printStackTrace(); 42 } 43 System.out.println("the program is running here!"); 44 } 45 } 46 /* 47 F:java_examplelesson61>java TestException 48 Error ~ DivideByMinusException 49 DivideByMinusException: the divisor is negative -1 50 at Test.divide(Test.java:6) 51 at TestException.main(Test.java:25) 52 the program is running here! 53 */
上述代码,若没有发生异常就不进入任何catch,如果try中语句发生了异常,且该异常没有对应的catch,那么它就会执行Exception的catch,也就是我们代码中最后一个catch,因为所有的异常都是Exception的子类。也正因为如此,我们Exception对应的catch只能放在最后,如果不是放在最后,则程序编译错误,如下所示
1 class Test 2 { 3 public int divide(int x,int y) throws ArithmeticException,DivideByMinusException 4 { 5 if(y<0) 6 throw new DivideByMinusException("the divisor is negative "+y); 7 //这里抛出的异常对象,就是catch(Exception e)中的e 8 int result=x/y; 9 return result; 10 } 11 } 12 class DivideByMinusException extends Exception 13 { 14 public DivideByMinusException(String msg) 15 { 16 super(msg); 17 } 18 } 19 class TestException 20 { 21 public static void main(String [] args) 22 { 23 Test t=new Test(); 24 try{ 25 t.divide(2,1); 26 System.out.println("the divide opration is over"); 27 } 28 catch(Exception e) 29 { 30 System.out.println(e.getMessage());//打印出the divisor is negative -1 31 e.printStackTrace(); 32 } 33 catch(ArithmeticException e) 34 { 35 System.out.println("Error ~ ArithmeticException"); 36 e.printStackTrace();//Exception类中的方法 37 } 38 39 catch(DivideByMinusException e) 40 { 41 System.out.println("Error ~ DivideByMinusException"); 42 e.printStackTrace(); 43 } 44 /*catch(Exception e) 45 { 46 System.out.println(e.getMessage());//打印出the divisor is negative -1 47 e.printStackTrace(); 48 }*/ 49 System.out.println("the program is running here!"); 50 } 51 } 52 /* 53 F:java_examplelesson61>javac Test.java 54 Test.java:33: 错误: 已捕获到异常错误ArithmeticException 55 catch(ArithmeticException e) 56 ^ 57 Test.java:39: 错误: 已捕获到异常错误DivideByMinusException 58 catch(DivideByMinusException e) 59 ^ 60 2 个错误 61 */
在实际应用中,我们可以通过try...catch来实现程序的跳转,下面例子中并不是真的有异常,而是我们利用try...catch的特点实现跳转
1 void fun 2 { 3 try{ 4 if (x==0) 5 throw new XxxException("Xxx"); 6 else 7 throw new YyyException("Yyy"); 8 } 9 catch(XxxException e) 10 {...} 11 catch(YyyException e) 12 {...} 13 }
finally关键字
使用这个关键字,在一般情况下不管程序是跳转到了哪种异常或者是没有异常,都会去执行finally中的代码块。那么问题来了,我catch后面的最后一个输出语句,也是不论有没有异常也会执行啊,何必要用一个finally呢?下面我们来看区别
1 class Test 2 { 3 public int divide(int x,int y) throws ArithmeticException,DivideByMinusException 4 { 5 if(y<0) 6 throw new DivideByMinusException("the divisor is negative "+y); 7 //这里抛出的异常对象,就是catch(Exception e)中的e 8 int result=x/y; 9 return result; 10 } 11 } 12 class DivideByMinusException extends Exception 13 { 14 public DivideByMinusException(String msg) 15 { 16 super(msg); 17 } 18 } 19 class TestException 20 { 21 public static void main(String [] args) 22 { 23 Test t=new Test(); 24 try{ 25 t.divide(2,-1); 26 System.out.println("the divide opration is over"); 27 } 28 catch(ArithmeticException e) 29 { 30 System.out.println("Error ~ ArithmeticException"); 31 e.printStackTrace();//Exception类中的方法 32 } 33 34 catch(DivideByMinusException e) 35 { 36 System.out.println("Error ~ DivideByMinusException"); 37 e.printStackTrace(); 38 return;//结束函数,有返回值的返回值,所以不会打印出B 39 //System.exit(0);//表示程序到此终止 40 } 41 catch(Exception e) 42 { 43 System.out.println(e.getMessage());//打印出the divisor is negative -1 44 e.printStackTrace(); 45 } 46 finally 47 { 48 System.out.println("finally~");//A语句 49 } 50 System.out.println("the program is running here!");//B语句 51 } 52 } 53 /* 54 F:java_examplelesson61>java TestException 55 Error ~ DivideByMinusException 56 DivideByMinusException: the divisor is negative -1 57 at Test.divide(Test.java:6) 58 at TestException.main(Test.java:25) 59 finally~ 60 */
加了return之后,没有执行B,但执行了A,说明不管函数有没有返回,finally部分都是要执行的。只有一种情况下,finally不会被执行,就是加了System.exit(0),表明程序到此结束。
注意:当类中方法有进行异常处理,那其子类若覆盖该方法要么不进行异常处理,要么子类中异常是父类异常的子集。
引入异常机制,可以加强程序的安全性、强健性。