异常处理
运行下面的程序,你将会看见异常的出现:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public int division( int a, int b) {
return a / b;
}
}
class Test {
public static void main(String[] args) {
ExcepDemo = new ExcepDemo ();
System.out.println(e.division( 5 , 0 ));
}
}
Java程序在执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给java运行时系统,这个过程称为抛出(throw)异常
当java运行时系统接受到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程成为捕获(catch)异常。
如果java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的java程序也将退出。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public int division( int a, int b) {
return a / b;
}
}
class Test {
public static void main(String[] args) {
Excep e = new Excep();
System.out.println(e.division( 5 , 0 ));
// 由于上一步传入参数0,引发异常,导致java运行时系统终止,相应的java程序也将退出。
System.out.println( " finish " ); // 不能输出
}
}
try/catch/finally语句。将可能引发异常的代码放到try语句当中,然后在catch语句当中对所引发的异常条件进行处理。finally语句中放始终要执行的语句,例如上面的System.out.println("finish");
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public int division( int a, int b) {
return a / b;
}
public int method( int a , int b) {
return division(a,b);
}
}
class Test {
public static void main(String[] args) {
Excep ex = new Excep();
try {
ex.method( 5 , 0 );
} catch (Exception e) {
System.out.println( " 除数不能为0 " );
} finally {
System.out.println( " finally " );
}
System.out.println( " finish " );
}
}
// output:
除数不能为0
finally
finish
既然都能输出,那么为什么还要使用finally呢?
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public int division( int a, int b) {
return a / b;
}
public int method( int a , int b) {
return division(a,b);
}
}
class Test {
public static void main(String[] args) {
Excep ex = new Excep();
try {
ex.method( 5 , 1 );
return ; // 没有发生异常之前,在返回之前,肯定要去执行finally的语句
} catch (Exception e) {
System.out.println( " 除数不能为0 " );
} finally {
System.out.println( " finally " );
}
System.out.println( " finish " );
}
}
只有finally输出,没有除数不能为0和finish的输出。
一旦try中引发异常,那么程序就会跳转到catch中去执行。执行完catch之后,然后会继续执行catch下面的代码。
当然finally也不是在任何时候都会执行,当程序退出时就不执行了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public int division( int a, int b) {
return a / b;
}
public int method( int a , int b) {
return division(a,b);
}
}
class Test {
public static void main(String[] args) {
Excep ex = new Excep();
try {
ex.method( 5 , 0 );
} catch (Exception e) {
System.out.println(e.toString());
System.exit( 0 );
} finally {
System.out.println( " finally " );
}
}
}
用异常本身的方法打印异常信息
// System.out.println("除数不能为0"); // 程序员自己编写的。
System.out.println(e.getMessage()); // 获取异常本身的详细信息。
}
toString() 获取throwable的一个简短的描述
System.out.println(e.toString()); // 获取throwable的一个简短的描述。
}
Exception 重写了toString方法。e.toString()打印的异常信息比getMessage()详细些。
printStackTrace 可以将异常在代码中发生的一个位置打印出来。
e.printStackTrace(); // 将异常在代码中发生的一个位置打印出来
}
这样就方便管理人员进行维修和处理。和java虚拟机打印的异常是相似的。
捕获异常可以在一开始就捕获。
public int division( int a, int b) {
try {
return a / b;
} catch (ArithmeticException e) {
e.printStackTrace();
// return 0;
}
}
}
上面的代码对吗?
不对,缺少返回值。因为return a/b确实是返回了一个整型,但是这里其实是分两步执行的。首先执行a/b,再返回,但是如果这里a / b引发异常,程序跳转到catch语句当中,不能return 结果了。所以我们应该手动的去返回一个整型。可以将catch块中的注释打开就可以了。
抛出异常就是抛给它的调用者,调用者也应该抛出异常。
public int division( int a, int b) throws Exception{
return a / b;
}
public int method( int a , int b) throws Exception{
return division(a,b);
}
}
那么如果要在main方法中使用,main方法也要throws Exception
main()的调用者java运行时系统,打印异常发生的轨迹,然后终止程序的运行。
编写程序的时候为了节省时间,可以在main函数当中直接把异常抛给java运行时系统。但是在实际编写代码的时候,我们最好还是将异常自行捕获到,然后在自己的代码当中自己处理。得到准确的信息给用户或管理者。
捕获异常时应该注意顺序(先小后大)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
Excep ex = new Excep();
try {
ex.method( 5 , 0 );
} catch (ArithmeticException e1) {
System.out.println(e1.toString());
} catch (Exception e2) {
System.out.println(e2.toString());
}
}
捕捉到了异常对象之后直接抛出
try {
return a / b;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
抛出一个新的异常对象
try {
return a / b;
} catch (Exception e) {
e.printStackTrace();
throw new Exception("不能被0除");//抛出一个新的异常对象。
}
}
自定义异常类
所有的异常类必须都从Exception派生,Exception类是所有异常类的基类。
DiviserIsMinusException(String str){
super (str); // 调用基类的构造方法
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public int division( int a, int b) throws ArithmeticException,DiviserIsMinusException {
if (b < 0 ) {
throw new DiviserIsMinusException( " diviser can't be minus " );
}
return a / b;
}
public int method( int a , int b) throws ArithmeticException,DiviserIsMinusException {
return division(a,b);
}
}
如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常(注:构造方法除外)。
我们可以在方法声明时,声明一个不会抛出的一场,java编译器就会强迫方法的使用者对异常进行处理。这种方法通常用于abstractbase clas和interface中。